@@ -133,31 +133,73 @@ def convert_index_info_to_schema(index_info: Dict[str, Any]) -> Dict[str, Any]:
133
133
Dict[str, Any]: Schema dictionary.
134
134
"""
135
135
index_name = index_info ["index_name" ]
136
- prefixes = index_info ["index_definition" ][3 ][0 ]
136
+ prefixes = index_info ["index_definition" ][3 ]
137
+ # Normalize single-element prefix lists to string for backward compatibility
138
+ if isinstance (prefixes , list ) and len (prefixes ) == 1 :
139
+ prefixes = prefixes [0 ]
137
140
storage_type = index_info ["index_definition" ][1 ].lower ()
138
141
139
142
index_fields = index_info ["attributes" ]
140
143
141
144
def parse_vector_attrs (attrs ):
142
145
# Parse vector attributes from Redis FT.INFO output
143
- # Attributes start at position 6 as key-value pairs
146
+ # Format varies significantly between Redis versions:
147
+ # - Redis 6.2.6-v9: [... "VECTOR"] - no params returned by FT.INFO
148
+ # - Redis 6.2.x: [... "VECTOR", "FLAT", "6", "TYPE", "FLOAT32", "DIM", "3", ...]
149
+ # Position 6: algorithm value (e.g., "FLAT" or "HNSW")
150
+ # Position 7: param count
151
+ # Position 8+: key-value pairs
152
+ # - Redis 7.x+: [... "VECTOR", "ALGORITHM", "FLAT", "TYPE", "FLOAT32", "DIM", "3", ...]
153
+ # Position 6+: all key-value pairs
154
+
155
+ # Check if we have any attributes beyond the type declaration
156
+ if len (attrs ) <= 6 :
157
+ # Redis 6.2.6-v9 or similar: no vector params in FT.INFO
158
+ # Return None to signal we can't parse this field properly
159
+ return None
160
+
144
161
vector_attrs = {}
162
+ start_pos = 6
163
+
164
+ # Detect format: if position 6 looks like an algorithm value (not a key),
165
+ # we're dealing with the older format
166
+ if len (attrs ) > 6 :
167
+ pos6_str = str (attrs [6 ]).upper ()
168
+ # Check if position 6 is an algorithm value (FLAT, HNSW) vs a key (ALGORITHM, TYPE, DIM)
169
+ if pos6_str in ("FLAT" , "HNSW" ):
170
+ # Old format (Redis 6.2.x): position 6 is algorithm value, position 7 is param count
171
+ # Store the algorithm
172
+ vector_attrs ["algorithm" ] = pos6_str
173
+ # Skip to position 8 where key-value pairs start
174
+ start_pos = 8
175
+
145
176
try :
146
- for i in range (6 , len (attrs ), 2 ):
177
+ for i in range (start_pos , len (attrs ), 2 ):
147
178
if i + 1 < len (attrs ):
148
179
key = str (attrs [i ]).lower ()
149
180
vector_attrs [key ] = attrs [i + 1 ]
150
181
except (IndexError , TypeError , ValueError ):
182
+ # Silently continue - we'll validate required fields below
151
183
pass
152
184
153
185
# Normalize to expected field names
154
186
normalized = {}
155
187
156
- # Handle dims/dim field
188
+ # Handle dims/dim field - REQUIRED for vector fields
157
189
if "dim" in vector_attrs :
158
190
normalized ["dims" ] = int (vector_attrs .pop ("dim" ))
159
191
elif "dims" in vector_attrs :
160
192
normalized ["dims" ] = int (vector_attrs ["dims" ])
193
+ else :
194
+ # If dims is missing from normal parsing, try scanning the raw attrs
195
+ # This handles edge cases where the format is unexpected
196
+ for i in range (6 , len (attrs ) - 1 ):
197
+ if str (attrs [i ]).upper () in ("DIM" , "DIMS" ):
198
+ try :
199
+ normalized ["dims" ] = int (attrs [i + 1 ])
200
+ break
201
+ except (ValueError , IndexError ):
202
+ pass
161
203
162
204
# Handle distance_metric field
163
205
if "distance_metric" in vector_attrs :
@@ -178,10 +220,18 @@ def parse_vector_attrs(attrs):
178
220
normalized ["datatype" ] = vector_attrs ["data_type" ].lower ()
179
221
elif "datatype" in vector_attrs :
180
222
normalized ["datatype" ] = vector_attrs ["datatype" ].lower ()
223
+ elif "type" in vector_attrs :
224
+ # Sometimes it's just "type" instead of "data_type"
225
+ normalized ["datatype" ] = vector_attrs ["type" ].lower ()
181
226
else :
182
227
# Default to float32 if missing
183
228
normalized ["datatype" ] = "float32"
184
229
230
+ # Validate that we have required dims
231
+ if "dims" not in normalized :
232
+ # Could not parse dims - this field is not properly supported
233
+ return None
234
+
185
235
return normalized
186
236
187
237
def parse_attrs (attrs , field_type = None ):
@@ -234,7 +284,12 @@ def parse_attrs(attrs, field_type=None):
234
284
field ["path" ] = field_attrs [1 ]
235
285
# parse field attrs
236
286
if field_attrs [5 ] == "VECTOR" :
237
- field ["attrs" ] = parse_vector_attrs (field_attrs )
287
+ attrs = parse_vector_attrs (field_attrs )
288
+ if attrs is None :
289
+ # Vector field attributes cannot be parsed on this Redis version
290
+ # Skip this field - it cannot be properly reconstructed
291
+ continue
292
+ field ["attrs" ] = attrs
238
293
else :
239
294
field ["attrs" ] = parse_attrs (field_attrs , field_type = field_attrs [5 ])
240
295
# append field
0 commit comments