Skip to content

Commit b1c39fe

Browse files
fix: Hybrid Search, minor changes, added experimental notice (#3132)
* Hybrid Search, minor changes, added experimental notice * fixed twot tests
1 parent 100c039 commit b1c39fe

File tree

2 files changed

+27
-71
lines changed

2 files changed

+27
-71
lines changed

packages/search/lib/commands/HYBRID.spec.ts

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,10 @@ describe('FT.HYBRID', () => {
1010
HYBRID.parseCommand(parser, 'index');
1111
assert.deepEqual(
1212
parser.redisArgs,
13-
['FT.HYBRID', 'index', '2', 'DIALECT', '2']
13+
['FT.HYBRID', 'index']
1414
);
1515
});
1616

17-
it('with count expressions', () => {
18-
const parser = new BasicCommandParser();
19-
HYBRID.parseCommand(parser, 'index', {
20-
countExpressions: 3
21-
});
22-
assert.deepEqual(
23-
parser.redisArgs,
24-
['FT.HYBRID', 'index', '3', 'DIALECT', '2']
25-
);
26-
});
2717

2818
it('with SEARCH expression', () => {
2919
const parser = new BasicCommandParser();
@@ -34,7 +24,7 @@ describe('FT.HYBRID', () => {
3424
});
3525
assert.deepEqual(
3626
parser.redisArgs,
37-
['FT.HYBRID', 'index', '2', 'SEARCH', '@description: bikes', 'DIALECT', '2']
27+
['FT.HYBRID', 'index', 'SEARCH', '@description: bikes']
3828
);
3929
});
4030

@@ -53,9 +43,9 @@ describe('FT.HYBRID', () => {
5343
assert.deepEqual(
5444
parser.redisArgs,
5545
[
56-
'FT.HYBRID', 'index', '2', 'SEARCH', '@description: bikes',
46+
'FT.HYBRID', 'index', 'SEARCH', '@description: bikes',
5747
'SCORER', 'TFIDF.DOCNORM', 'param1', 'param2',
58-
'YIELD_SCORE_AS', 'search_score', 'DIALECT', '2'
48+
'YIELD_SCORE_AS', 'search_score'
5949
]
6050
);
6151
});
@@ -78,9 +68,8 @@ describe('FT.HYBRID', () => {
7868
assert.deepEqual(
7969
parser.redisArgs,
8070
[
81-
'FT.HYBRID', 'index', '2', 'VSIM', '@vector_field', 'BLOB_DATA',
82-
'KNN', '1', 'K', '10', 'EF_RUNTIME', '50', 'YIELD_DISTANCE_AS', 'vector_dist',
83-
'DIALECT', '2'
71+
'FT.HYBRID', 'index', 'VSIM', '@vector_field', 'BLOB_DATA',
72+
'KNN', '1', 'K', '10', 'EF_RUNTIME', '50', 'YIELD_DISTANCE_AS', 'vector_dist'
8473
]
8574
);
8675
});
@@ -103,9 +92,8 @@ describe('FT.HYBRID', () => {
10392
assert.deepEqual(
10493
parser.redisArgs,
10594
[
106-
'FT.HYBRID', 'index', '2', 'VSIM', '@vector_field', 'BLOB_DATA',
107-
'RANGE', '1', 'RADIUS', '0.5', 'EPSILON', '0.01', 'YIELD_DISTANCE_AS', 'vector_dist',
108-
'DIALECT', '2'
95+
'FT.HYBRID', 'index', 'VSIM', '@vector_field', 'BLOB_DATA',
96+
'RANGE', '1', 'RADIUS', '0.5', 'EPSILON', '0.01', 'YIELD_DISTANCE_AS', 'vector_dist'
10997
]
11098
);
11199
});
@@ -129,9 +117,9 @@ describe('FT.HYBRID', () => {
129117
assert.deepEqual(
130118
parser.redisArgs,
131119
[
132-
'FT.HYBRID', 'index', '2', 'VSIM', '@vector_field', 'BLOB_DATA',
120+
'FT.HYBRID', 'index', 'VSIM', '@vector_field', 'BLOB_DATA',
133121
'FILTER', '@category:{bikes}', 'POLICY', 'BATCHES', 'BATCHES', 'BATCH_SIZE', '100',
134-
'YIELD_SCORE_AS', 'vsim_score', 'DIALECT', '2'
122+
'YIELD_SCORE_AS', 'vsim_score'
135123
]
136124
);
137125
});
@@ -153,8 +141,8 @@ describe('FT.HYBRID', () => {
153141
assert.deepEqual(
154142
parser.redisArgs,
155143
[
156-
'FT.HYBRID', 'index', '2', 'COMBINE', 'RRF', '2', 'WINDOW', '10', 'CONSTANT', '60',
157-
'YIELD_SCORE_AS', 'combined_score', 'DIALECT', '2'
144+
'FT.HYBRID', 'index', 'COMBINE', 'RRF', '2', 'WINDOW', '10', 'CONSTANT', '60',
145+
'YIELD_SCORE_AS', 'combined_score'
158146
]
159147
);
160148
});
@@ -175,8 +163,7 @@ describe('FT.HYBRID', () => {
175163
assert.deepEqual(
176164
parser.redisArgs,
177165
[
178-
'FT.HYBRID', 'index', '2', 'COMBINE', 'LINEAR', '2', 'ALPHA', '0.7', 'BETA', '0.3',
179-
'DIALECT', '2'
166+
'FT.HYBRID', 'index', 'COMBINE', 'LINEAR', '2', 'ALPHA', '0.7', 'BETA', '0.3'
180167
]
181168
);
182169
});
@@ -199,8 +186,8 @@ describe('FT.HYBRID', () => {
199186
assert.deepEqual(
200187
parser.redisArgs,
201188
[
202-
'FT.HYBRID', 'index', '2', 'LOAD', '2', 'field1', 'field2',
203-
'SORTBY', '1', 'score', 'DESC', 'LIMIT', '0', '10', 'DIALECT', '2'
189+
'FT.HYBRID', 'index', 'LOAD', '2', 'field1', 'field2',
190+
'SORTBY', '1', 'score', 'DESC', 'LIMIT', '0', '10'
204191
]
205192
);
206193
});
@@ -220,8 +207,7 @@ describe('FT.HYBRID', () => {
220207
assert.deepEqual(
221208
parser.redisArgs,
222209
[
223-
'FT.HYBRID', 'index', '2', 'GROUPBY', '1', '@category', 'REDUCE', 'COUNT', '0',
224-
'DIALECT', '2'
210+
'FT.HYBRID', 'index', 'GROUPBY', '1', '@category', 'REDUCE', 'COUNT', '0'
225211
]
226212
);
227213
});
@@ -236,7 +222,7 @@ describe('FT.HYBRID', () => {
236222
});
237223
assert.deepEqual(
238224
parser.redisArgs,
239-
['FT.HYBRID', 'index', '2', 'APPLY', '@score * 2', 'AS', 'double_score', 'DIALECT', '2']
225+
['FT.HYBRID', 'index', 'APPLY', '@score * 2', 'AS', 'double_score']
240226
);
241227
});
242228

@@ -247,7 +233,7 @@ describe('FT.HYBRID', () => {
247233
});
248234
assert.deepEqual(
249235
parser.redisArgs,
250-
['FT.HYBRID', 'index', '2', 'FILTER', '@price:[100 500]', 'DIALECT', '2']
236+
['FT.HYBRID', 'index', 'FILTER', '@price:[100 500]']
251237
);
252238
});
253239

@@ -262,8 +248,7 @@ describe('FT.HYBRID', () => {
262248
assert.deepEqual(
263249
parser.redisArgs,
264250
[
265-
'FT.HYBRID', 'index', '2', 'PARAMS', '4', 'query_vector', 'BLOB_DATA', 'min_price', '100',
266-
'DIALECT', '2'
251+
'FT.HYBRID', 'index', 'PARAMS', '4', 'query_vector', 'BLOB_DATA', 'min_price', '100'
267252
]
268253
);
269254
});
@@ -276,7 +261,7 @@ describe('FT.HYBRID', () => {
276261
});
277262
assert.deepEqual(
278263
parser.redisArgs,
279-
['FT.HYBRID', 'index', '2', 'EXPLAINSCORE', 'TIMEOUT', '5000', 'DIALECT', '2']
264+
['FT.HYBRID', 'index', 'EXPLAINSCORE', 'TIMEOUT', '5000']
280265
);
281266
});
282267

@@ -291,16 +276,14 @@ describe('FT.HYBRID', () => {
291276
assert.deepEqual(
292277
parser.redisArgs,
293278
[
294-
'FT.HYBRID', 'index', '2', 'WITHCURSOR', 'COUNT', '100', 'MAXIDLE', '300000',
295-
'DIALECT', '2'
279+
'FT.HYBRID', 'index', 'WITHCURSOR', 'COUNT', '100', 'MAXIDLE', '300000'
296280
]
297281
);
298282
});
299283

300284
it('complete example with all options', () => {
301285
const parser = new BasicCommandParser();
302286
HYBRID.parseCommand(parser, 'index', {
303-
countExpressions: 2,
304287
SEARCH: {
305288
query: '@description: bikes',
306289
SCORER: {
@@ -343,29 +326,17 @@ describe('FT.HYBRID', () => {
343326
assert.deepEqual(
344327
parser.redisArgs,
345328
[
346-
'FT.HYBRID', 'index', '2',
329+
'FT.HYBRID', 'index',
347330
'SEARCH', '@description: bikes', 'SCORER', 'TFIDF.DOCNORM', 'YIELD_SCORE_AS', 'text_score',
348331
'VSIM', '@vector_field', '$query_vector', 'KNN', '1', 'K', '5', 'YIELD_SCORE_AS', 'vector_score',
349332
'COMBINE', 'RRF', '2', 'CONSTANT', '60', 'YIELD_SCORE_AS', 'final_score',
350333
'LOAD', '2', 'description', 'price',
351334
'SORTBY', '1', 'final_score', 'DESC',
352335
'LIMIT', '0', '10',
353-
'PARAMS', '2', 'query_vector', 'BLOB_DATA',
354-
'DIALECT', '2'
336+
'PARAMS', '2', 'query_vector', 'BLOB_DATA'
355337
]
356338
);
357339
});
358-
359-
it('with custom DIALECT', () => {
360-
const parser = new BasicCommandParser();
361-
HYBRID.parseCommand(parser, 'index', {
362-
DIALECT: 3
363-
});
364-
assert.deepEqual(
365-
parser.redisArgs,
366-
['FT.HYBRID', 'index', '2', 'DIALECT', '3']
367-
);
368-
});
369340
});
370341

371342
// Integration tests would need to be added when RediSearch supports FT.HYBRID

packages/search/lib/commands/HYBRID.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { CommandParser } from '@redis/client/dist/lib/client/parser';
22
import { RedisArgument, Command, ReplyUnion } from '@redis/client/dist/lib/RESP/types';
33
import { RedisVariadicArgument, parseOptionalVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers';
4-
import { DEFAULT_DIALECT } from '../dialect/default';
54
import { FtSearchParams, parseParamsArgument } from './SEARCH';
65

76
export interface FtHybridSearchExpression {
@@ -55,7 +54,6 @@ export interface FtHybridCombineMethod {
5554
}
5655

5756
export interface FtHybridOptions {
58-
countExpressions?: number;
5957
SEARCH?: FtHybridSearchExpression;
6058
VSIM?: FtHybridVectorExpression;
6159
COMBINE?: {
@@ -94,7 +92,6 @@ export interface FtHybridOptions {
9492
COUNT?: number;
9593
MAXIDLE?: number;
9694
};
97-
DIALECT?: number;
9895
}
9996

10097
function parseSearchExpression(parser: CommandParser, search: FtHybridSearchExpression) {
@@ -269,10 +266,6 @@ function parseHybridOptions(parser: CommandParser, options?: FtHybridOptions) {
269266
parser.push('MAXIDLE', options.WITHCURSOR.MAXIDLE.toString());
270267
}
271268
}
272-
273-
if (options?.DIALECT) {
274-
parser.push('DIALECT', options.DIALECT.toString());
275-
}
276269
}
277270

278271
export default {
@@ -282,10 +275,12 @@ export default {
282275
* Performs a hybrid search combining multiple search expressions.
283276
* Supports multiple SEARCH and VECTOR expressions with various fusion methods.
284277
*
278+
* NOTE: FT.Hybrid is still in experimental state
279+
* It's behavioud and function signature may change`
280+
*
285281
* @param parser - The command parser
286282
* @param index - The index name to search
287283
* @param options - Hybrid search options including:
288-
* - countExpressions: Number of expressions (default 2)
289284
* - SEARCH: Text search expression with optional scoring
290285
* - VSIM: Vector similarity expression with KNN/RANGE methods
291286
* - COMBINE: Fusion method (RRF, LINEAR, FUNCTION)
@@ -295,18 +290,8 @@ export default {
295290
parseCommand(parser: CommandParser, index: RedisArgument, options?: FtHybridOptions) {
296291
parser.push('FT.HYBRID', index);
297292

298-
if (options?.countExpressions !== undefined) {
299-
parser.push(options.countExpressions.toString());
300-
} else {
301-
parser.push('2'); // Default to 2 expressions
302-
}
303-
304293
parseHybridOptions(parser, options);
305-
306-
// Always add DIALECT at the end if not already added
307-
if (!options?.DIALECT) {
308-
parser.push('DIALECT', DEFAULT_DIALECT);
309-
}
294+
310295
},
311296
transformReply: {
312297
2: (reply: any): any => {

0 commit comments

Comments
 (0)