@@ -591,7 +591,7 @@ else if (fieldType == Point.class) {
591
591
field .getName () :
592
592
String .join ("." , prefix , field .getName ());
593
593
594
- // For nested fields, automatically create index fields even without explicit annotations
594
+ // For nested fields, automatically create index fields when the parent field is annotated with @Indexed(schemaFieldType = SchemaFieldType.NESTED)
595
595
fields .addAll (createNestedIndexFields (field , subfield , subfieldPrefix , isDocument ));
596
596
}
597
597
}
@@ -887,6 +887,32 @@ private List<SearchField> getNestedField(String fieldPrefix, java.lang.reflect.F
887
887
return fieldList ;
888
888
}
889
889
890
+ /**
891
+ * Determines the appropriate FieldType for a given Java class.
892
+ * This utility method centralizes the logic for mapping Java types to Redis field types.
893
+ */
894
+ private enum FieldTypeMapper {
895
+ TAG ,
896
+ NUMERIC ,
897
+ GEO ,
898
+ UNSUPPORTED ;
899
+
900
+ static FieldTypeMapper getFieldType (Class <?> fieldType ) {
901
+ if (CharSequence .class .isAssignableFrom (
902
+ fieldType ) || fieldType == Boolean .class || fieldType == UUID .class || fieldType == Ulid .class || fieldType
903
+ .isEnum ()) {
904
+ return TAG ;
905
+ } else if (Number .class .isAssignableFrom (
906
+ fieldType ) || fieldType == LocalDateTime .class || fieldType == LocalDate .class || fieldType == Date .class || fieldType == Instant .class || fieldType == OffsetDateTime .class ) {
907
+ return NUMERIC ;
908
+ } else if (fieldType == Point .class ) {
909
+ return GEO ;
910
+ } else {
911
+ return UNSUPPORTED ;
912
+ }
913
+ }
914
+ }
915
+
890
916
/**
891
917
* Creates index fields for nested array elements automatically.
892
918
* This method handles automatic indexing of all fields within nested objects
@@ -900,62 +926,48 @@ private List<SearchField> createNestedIndexFields(java.lang.reflect.Field arrayF
900
926
901
927
// For nested arrays, the path should be: $.arrayField[*].nestedField
902
928
// The prefix already contains the array field name, so we just need [*].nestedField
929
+ // JSON documents use a "$" prefix to denote the root of the document, while hash structures do not.
930
+ // The `isDocument` flag determines whether the entity is stored as a JSON document or a hash structure in Redis.
931
+ // This affects the field path format: JSON documents require "$." as the prefix, while hash structures do not.
903
932
String fullFieldPath = isDocument ?
904
933
"$." + arrayField .getName () + "[*]." + nestedField .getName () :
905
934
arrayField .getName () + "[*]." + nestedField .getName ();
906
935
907
936
logger .info (String .format ("Creating automatic nested field index: %s -> %s" , arrayField .getName (), fullFieldPath ));
908
937
909
938
// Determine field type and create appropriate index field
910
- if (CharSequence .class .isAssignableFrom (
911
- nestedFieldType ) || nestedFieldType == Boolean .class || nestedFieldType == UUID .class || nestedFieldType == Ulid .class ) {
912
-
913
- // Create TAG field for strings, booleans, UUIDs, and ULIDs
914
- FieldName fieldName = FieldName .of (fullFieldPath );
915
- String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
916
- if (alias != null && !alias .isEmpty ()) {
917
- fieldName = fieldName .as (alias );
918
- }
919
-
920
- fields .add (SearchField .of (arrayField , getTagField (fieldName , "|" , false )));
921
-
922
- } else if (Number .class .isAssignableFrom (
923
- nestedFieldType ) || nestedFieldType == LocalDateTime .class || nestedFieldType == LocalDate .class || nestedFieldType == Date .class || nestedFieldType == Instant .class || nestedFieldType == OffsetDateTime .class ) {
924
-
925
- // Create NUMERIC field for numbers and dates
926
- FieldName fieldName = FieldName .of (fullFieldPath );
927
- String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
928
- if (alias != null && !alias .isEmpty ()) {
929
- fieldName = fieldName .as (alias );
939
+ FieldTypeMapper fieldTypeMapper = FieldTypeMapper .getFieldType (nestedFieldType );
940
+
941
+ switch (fieldTypeMapper ) {
942
+ case TAG -> {
943
+ // Create TAG field for strings, booleans, UUIDs, ULIDs, and enums
944
+ FieldName fieldName = FieldName .of (fullFieldPath );
945
+ String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
946
+ if (alias != null && !alias .isEmpty ()) {
947
+ fieldName = fieldName .as (alias );
948
+ }
949
+ fields .add (SearchField .of (arrayField , getTagField (fieldName , "|" , false )));
930
950
}
931
-
932
- fields .add (SearchField .of (arrayField , NumericField .of (fieldName )));
933
-
934
- } else if (nestedFieldType == Point .class ) {
935
-
936
- // Create GEO field for Point objects
937
- FieldName fieldName = FieldName .of (fullFieldPath );
938
- String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
939
- if (alias != null && !alias .isEmpty ()) {
940
- fieldName = fieldName .as (alias );
951
+ case NUMERIC -> {
952
+ // Create NUMERIC field for numbers and dates
953
+ FieldName fieldName = FieldName .of (fullFieldPath );
954
+ String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
955
+ if (alias != null && !alias .isEmpty ()) {
956
+ fieldName = fieldName .as (alias );
957
+ }
958
+ fields .add (SearchField .of (arrayField , NumericField .of (fieldName )));
941
959
}
942
-
943
- fields .add (SearchField .of (arrayField , GeoField .of (fieldName )));
944
-
945
- } else if (nestedFieldType .isEnum ()) {
946
-
947
- // Create TAG field for enums
948
- FieldName fieldName = FieldName .of (fullFieldPath );
949
- String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
950
- if (alias != null && !alias .isEmpty ()) {
951
- fieldName = fieldName .as (alias );
960
+ case GEO -> {
961
+ // Create GEO field for Point objects
962
+ FieldName fieldName = FieldName .of (fullFieldPath );
963
+ String alias = QueryUtils .searchIndexFieldAliasFor (nestedField , prefix );
964
+ if (alias != null && !alias .isEmpty ()) {
965
+ fieldName = fieldName .as (alias );
966
+ }
967
+ fields .add (SearchField .of (arrayField , GeoField .of (fieldName )));
952
968
}
953
-
954
- fields .add (SearchField .of (arrayField , getTagField (fieldName , "|" , false )));
955
-
956
- } else {
957
- logger .debug (String .format ("Skipping nested field %s of unsupported type %s" , nestedField .getName (),
958
- nestedFieldType .getSimpleName ()));
969
+ case UNSUPPORTED -> logger .debug (String .format ("Skipping nested field %s of unsupported type %s" , nestedField
970
+ .getName (), nestedFieldType .getSimpleName ()));
959
971
}
960
972
961
973
return fields ;
0 commit comments