@@ -47,7 +47,7 @@ public class RediSearchIndexer {
4747 private final Map <String , Class <?>> keyspaceToEntityClass = new ConcurrentHashMap <>();
4848 private final Map <Class <?>, String > entityClassToKeySpace = new ConcurrentHashMap <>();
4949 private final List <Class <?>> indexedEntityClasses = new ArrayList <>();
50- private final Map <Class <?>,Schema > entityClassToSchema = new ConcurrentHashMap <>();
50+ private final Map <Class <?>, Schema > entityClassToSchema = new ConcurrentHashMap <>();
5151
5252 private static final Log logger = LogFactory .getLog (RediSearchIndexer .class );
5353
@@ -97,7 +97,8 @@ public void createIndexFor(Class<?> cl) {
9797 indexName = cl .getName () + "Idx" ;
9898 logger .info (String .format ("Found @%s annotated class: %s" , idxType , cl .getName ()));
9999
100- final List <java .lang .reflect .Field > allClassFields = com .redis .om .spring .util .ObjectUtils .getDeclaredFieldsTransitively (cl );
100+ final List <java .lang .reflect .Field > allClassFields = com .redis .om .spring .util .ObjectUtils
101+ .getDeclaredFieldsTransitively (cl );
101102
102103 List <Field > fields = new ArrayList <>();
103104
@@ -115,7 +116,8 @@ public void createIndexFor(Class<?> cl) {
115116 if (maybeIdField .isPresent ()) {
116117 java .lang .reflect .Field idField = maybeIdField .get ();
117118 // Only auto-index the @Id if not already indexed by the user (gh-135)
118- if (!idField .isAnnotationPresent (Indexed .class ) && !idField .isAnnotationPresent (Searchable .class ) && (fields .stream ().noneMatch (f -> f .name .equals (idField .getName ())))) {
119+ if (!idField .isAnnotationPresent (Indexed .class ) && !idField .isAnnotationPresent (Searchable .class )
120+ && (fields .stream ().noneMatch (f -> f .name .equals (idField .getName ())))) {
119121 if (Number .class .isAssignableFrom (idField .getType ())) {
120122 fields
121123 .add (indexAsNumericFieldFor (maybeIdField .get (), idxType == IndexDefinition .Type .JSON , "" , true ,
@@ -239,12 +241,15 @@ private List<Field> findIndexFields(java.lang.reflect.Field field, String prefix
239241 // Any Character class, Enums or Boolean -> Tag Search Field
240242 //
241243 if (CharSequence .class .isAssignableFrom (fieldType ) || (fieldType == Boolean .class ) || (fieldType .isEnum ())) {
242- fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (), indexed .arrayIndex ()));
244+ fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (),
245+ indexed .arrayIndex ()));
243246 }
244247 //
245248 // Any Numeric class -> Numeric Search Field
246249 //
247- else if (Number .class .isAssignableFrom (fieldType ) || (fieldType == LocalDateTime .class ) || (field .getType () == LocalDate .class ) || (field .getType () == Date .class ) || (field .getType () == Instant .class )) {
250+ else if (Number .class .isAssignableFrom (fieldType ) || (fieldType == LocalDateTime .class )
251+ || (field .getType () == LocalDate .class ) || (field .getType () == Date .class )
252+ || (field .getType () == Instant .class )) {
248253 fields .add (indexAsNumericFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .noindex ()));
249254 }
250255 //
@@ -263,7 +268,8 @@ else if (Set.class.isAssignableFrom(fieldType) || List.class.isAssignableFrom(fi
263268 Class <?> collectionType = maybeCollectionType .get ();
264269
265270 if (CharSequence .class .isAssignableFrom (collectionType ) || (collectionType == Boolean .class )) {
266- fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (), indexed .arrayIndex ()));
271+ fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (),
272+ indexed .arrayIndex ()));
267273 // Index nested fields
268274 } else if (isDocument ) {
269275 if (Number .class .isAssignableFrom (collectionType )) {
@@ -291,25 +297,27 @@ else if (fieldType == Point.class) {
291297 // Recursively explore the fields for Index annotated fields
292298 //
293299 else {
294- for (java .lang .reflect .Field subfield : com .redis .om .spring .util .ObjectUtils . getDeclaredFieldsTransitively ( field . getType ())) {
295- String subfieldPrefix = ( prefix == null || prefix . isBlank ()) ?
296- field .getName () :
297- String .join ("." , prefix , field .getName ());
300+ for (java .lang .reflect .Field subfield : com .redis .om .spring .util .ObjectUtils
301+ . getDeclaredFieldsTransitively ( field . getType ())) {
302+ String subfieldPrefix = ( prefix == null || prefix . isBlank ()) ? field .getName ()
303+ : String .join ("." , prefix , field .getName ());
298304 fields .addAll (findIndexFields (subfield , subfieldPrefix , isDocument ));
299305 }
300306 }
301307 } else { // Schema field type hardcoded/set in @Indexed
302308 switch (indexed .schemaFieldType ()) {
303309 case TAG ->
304- fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (), indexed .arrayIndex ()));
305- case NUMERIC -> fields .add (indexAsNumericFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .noindex ()));
310+ fields .add (indexAsTagFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .separator (),
311+ indexed .arrayIndex ()));
312+ case NUMERIC ->
313+ fields .add (indexAsNumericFieldFor (field , isDocument , prefix , indexed .sortable (), indexed .noindex ()));
306314 case GEO -> fields .add (indexAsGeoFieldFor (field , true , prefix , indexed .sortable (), indexed .noindex ()));
307315 case VECTOR -> fields .add (indexAsVectorFieldFor (field , isDocument , prefix , indexed ));
308316 case NESTED -> {
309- for (java .lang .reflect .Field subfield : com .redis .om .spring .util .ObjectUtils . getDeclaredFieldsTransitively ( field . getType ())) {
310- String subfieldPrefix = ( prefix == null || prefix . isBlank ()) ?
311- field .getName () :
312- String .join ("." , prefix , field .getName ());
317+ for (java .lang .reflect .Field subfield : com .redis .om .spring .util .ObjectUtils
318+ . getDeclaredFieldsTransitively ( field . getType ())) {
319+ String subfieldPrefix = ( prefix == null || prefix . isBlank ()) ? field .getName ()
320+ : String .join ("." , prefix , field .getName ());
313321 fields .addAll (findIndexFields (subfield , subfieldPrefix , isDocument ));
314322 }
315323 }
@@ -370,14 +378,15 @@ private Field indexAsTagFieldFor(java.lang.reflect.Field field, boolean isDocume
370378 return new TagField (fieldName , ti .separator (), false );
371379 }
372380
373- private Field indexAsVectorFieldFor (java .lang .reflect .Field field , boolean isDocument , String prefix , Indexed indexed ) {
381+ private Field indexAsVectorFieldFor (java .lang .reflect .Field field , boolean isDocument , String prefix ,
382+ Indexed indexed ) {
374383 TypeInformation <?> typeInfo = TypeInformation .of (field .getType ());
375384 String fieldPrefix = getFieldPrefix (prefix , isDocument );
376385
377386 String fieldPostfix = (isDocument && typeInfo .isCollectionLike () && !field .isAnnotationPresent (JsonAdapter .class ))
378387 ? "[*]"
379388 : "" ;
380- String fieldName =fieldPrefix + field .getName () + fieldPostfix ;
389+ String fieldName = fieldPrefix + field .getName () + fieldPostfix ;
381390
382391 Map <String , Object > attributes = new HashMap <>();
383392 attributes .put ("TYPE" , indexed .type ().toString ());
@@ -416,14 +425,15 @@ private Field indexAsVectorFieldFor(java.lang.reflect.Field field, boolean isDoc
416425 return vectorField ;
417426 }
418427
419- private Field indexAsVectorFieldFor (java .lang .reflect .Field field , boolean isDocument , String prefix , VectorIndexed vi ) {
428+ private Field indexAsVectorFieldFor (java .lang .reflect .Field field , boolean isDocument , String prefix ,
429+ VectorIndexed vi ) {
420430 TypeInformation <?> typeInfo = TypeInformation .of (field .getType ());
421431 String fieldPrefix = getFieldPrefix (prefix , isDocument );
422432
423433 String fieldPostfix = (isDocument && typeInfo .isCollectionLike () && !field .isAnnotationPresent (JsonAdapter .class ))
424434 ? "[*]"
425435 : "" ;
426- String fieldName =fieldPrefix + field .getName () + fieldPostfix ;
436+ String fieldName = fieldPrefix + field .getName () + fieldPostfix ;
427437
428438 Map <String , Object > attributes = new HashMap <>();
429439 attributes .put ("TYPE" , vi .type ().toString ());
@@ -566,7 +576,8 @@ private List<Field> getNestedField(String fieldPrefix, java.lang.reflect.Field f
566576 Type genericType = field .getGenericType ();
567577 if (genericType instanceof ParameterizedType pt ) {
568578 Class <?> actualTypeArgument = (Class <?>) pt .getActualTypeArguments ()[0 ];
569- List <java .lang .reflect .Field > subDeclaredFields = com .redis .om .spring .util .ObjectUtils .getDeclaredFieldsTransitively (actualTypeArgument );
579+ List <java .lang .reflect .Field > subDeclaredFields = com .redis .om .spring .util .ObjectUtils
580+ .getDeclaredFieldsTransitively (actualTypeArgument );
570581 String tempPrefix = "" ;
571582 if (prefix == null ) {
572583 prefix = field .getName ();
@@ -613,6 +624,22 @@ else if (Number.class.isAssignableFrom(subField.getType()) || (subField.getType(
613624 logger .info (String .format ("Creating nested relationships: %s -> %s" , field .getName (), subField .getName ()));
614625 fieldList .add (new Field (fieldName , FieldType .NUMERIC ));
615626 }
627+ } else if (subField .isAnnotationPresent (Searchable .class )) {
628+ Searchable searchable = subField .getAnnotation (Searchable .class );
629+ tempPrefix = field .getName () + "[0:]." ;
630+
631+ FieldName fieldName = FieldName .of (fieldPrefix + tempPrefix + subField .getName ());
632+ fieldName = fieldName .as (QueryUtils .searchIndexFieldAliasFor (subField , prefix ));
633+
634+ logger
635+ .info (String .format ("Creating TEXT nested relationships: %s -> %s" , field .getName (), subField .getName ()));
636+
637+ String phonetic = ObjectUtils .isEmpty (searchable .phonetic ()) ? null : searchable .phonetic ();
638+
639+ fieldList .add (new TextField (fieldName , searchable .weight (), searchable .sortable (), searchable .nostem (),
640+ searchable .noindex (), phonetic ));
641+
642+ continue ;
616643 }
617644 getNestedField (fieldPrefix + tempPrefix , subField , prefix , fieldList );
618645 }
0 commit comments