1+ // EXAMPLE: query_combined
2+ // HIDE_START
3+ import assert from 'node:assert' ;
4+ import fs from 'node:fs' ;
5+ import { createClient } from 'redis' ;
6+ import { SchemaFieldTypes , VectorAlgorithms } from '@redis/search' ;
7+ import { pipeline } from '@xenova/transformers' ;
8+
9+ function float32Buffer ( arr ) {
10+ const floatArray = new Float32Array ( arr ) ;
11+ const float32Buffer = Buffer . from ( floatArray . buffer ) ;
12+ return float32Buffer ;
13+ }
14+
15+ async function embedText ( sentence ) {
16+ let modelName = 'Xenova/all-MiniLM-L6-v2' ;
17+ let pipe = await pipeline ( 'feature-extraction' , modelName ) ;
18+
19+ let vectorOutput = await pipe ( sentence , {
20+ pooling : 'mean' ,
21+ normalize : true ,
22+ } ) ;
23+
24+ if ( vectorOutput == null ) {
25+ throw new Error ( 'vectorOutput is undefined' ) ;
26+ }
27+
28+ const embedding = Object . values ( vectorOutput . data ) ;
29+
30+ return embedding ;
31+ }
32+
33+ let query = 'Bike for small kids' ;
34+ let vector_query = float32Buffer ( await embedText ( 'That is a very happy person' ) ) ;
35+
36+ const client = createClient ( ) ;
37+ await client . connect ( ) . catch ( console . error ) ;
38+
39+ // create index
40+ await client . ft . create ( 'idx:bicycle' , {
41+ '$.description' : {
42+ type : SchemaFieldTypes . TEXT ,
43+ AS : 'description'
44+ } ,
45+ '$.condition' : {
46+ type : SchemaFieldTypes . TAG ,
47+ AS : 'condition'
48+ } ,
49+ '$.price' : {
50+ type : SchemaFieldTypes . NUMERIC ,
51+ AS : 'price'
52+ } ,
53+ '$.description_embeddings' : {
54+ type : SchemaFieldTypes . VECTOR ,
55+ TYPE : 'FLOAT32' ,
56+ ALGORITHM : VectorAlgorithms . FLAT ,
57+ DIM : 384 ,
58+ DISTANCE_METRIC : 'COSINE' ,
59+ AS : 'vector' ,
60+ }
61+ } , {
62+ ON : 'JSON' ,
63+ PREFIX : 'bicycle:'
64+ } ) ;
65+
66+ // load data
67+ const bicycles = JSON . parse ( fs . readFileSync ( 'data/query_vector.json' , 'utf8' ) ) ;
68+
69+ await Promise . all (
70+ bicycles . map ( ( bicycle , bid ) => {
71+ return client . json . set ( `bicycle:${ bid } ` , '$' , bicycle ) ;
72+ } )
73+ ) ;
74+ // HIDE_END
75+
76+ // STEP_START combined1
77+ const res1 = await client . ft . search ( 'idx:bicycle' , '@price:[500 1000] @condition:{new}' ) ;
78+ console . log ( res1 . total ) ; // >>> 1
79+ console . log ( res1 ) ; // >>>
80+ //{
81+ // total: 1,
82+ // documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
83+ //}
84+ // REMOVE_START
85+ assert . strictEqual ( res1 . total , 1 ) ;
86+ // REMOVE_END
87+ // STEP_END
88+
89+ // STEP_START combined2
90+ const res2 = await client . ft . search ( 'idx:bicycle' , 'kids @price:[500 1000] @condition:{used}' ) ;
91+ console . log ( res2 . total ) ; // >>> 1
92+ console . log ( res2 ) ; // >>>
93+ // {
94+ // total: 1,
95+ // documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
96+ // }
97+ // REMOVE_START
98+ assert . strictEqual ( res2 . total , 1 ) ;
99+ // REMOVE_END
100+ // STEP_END
101+
102+ // STEP_START combined3
103+ const res3 = await client . ft . search ( 'idx:bicycle' , '(kids | small) @condition:{used}' ) ;
104+ console . log ( res3 . total ) ; // >>> 2
105+ console . log ( res3 ) ; // >>>
106+ //{
107+ // total: 2,
108+ // documents: [
109+ // { id: 'bicycle:2', value: [Object: null prototype] },
110+ // { id: 'bicycle:1', value: [Object: null prototype] }
111+ // ]
112+ //}
113+ // REMOVE_START
114+ assert . strictEqual ( res3 . total , 2 ) ;
115+ // REMOVE_END
116+ // STEP_END
117+
118+ // STEP_START combined4
119+ const res4 = await client . ft . search ( 'idx:bicycle' , '@description:(kids | small) @condition:{used}' ) ;
120+ console . log ( res4 . total ) ; // >>> 2
121+ console . log ( res4 ) ; // >>>
122+ //{
123+ // total: 2,
124+ // documents: [
125+ // { id: 'bicycle:2', value: [Object: null prototype] },
126+ // { id: 'bicycle:1', value: [Object: null prototype] }
127+ // ]
128+ //}
129+ // REMOVE_START
130+ assert . strictEqual ( res4 . total , 2 ) ;
131+ // REMOVE_END
132+ // STEP_END
133+
134+ // STEP_START combined5
135+ const res5 = await client . ft . search ( 'idx:bicycle' , '@description:(kids | small) @condition:{new | used}' ) ;
136+ console . log ( res5 . total ) ; // >>> 3
137+ console . log ( res5 ) ; // >>>
138+ //{
139+ // total: 3,
140+ // documents: [
141+ // { id: 'bicycle:1', value: [Object: null prototype] },
142+ // { id: 'bicycle:0', value: [Object: null prototype] },
143+ // { id: 'bicycle:2', value: [Object: null prototype] }
144+ // ]
145+ //}
146+ // REMOVE_START
147+ assert . strictEqual ( res5 . total , 3 ) ;
148+ // REMOVE_END
149+ // STEP_END
150+
151+ // STEP_START combined6
152+ const res6 = await client . ft . search ( 'idx:bicycle' , '@price:[500 1000] -@condition:{new}' ) ;
153+ console . log ( res6 . total ) ; // >>> 2
154+ console . log ( res6 ) ; // >>>
155+ //{
156+ // total: 2,
157+ // documents: [
158+ // { id: 'bicycle:2', value: [Object: null prototype] },
159+ // { id: 'bicycle:9', value: [Object: null prototype] }
160+ // ]
161+ //}
162+ // REMOVE_START
163+ assert . strictEqual ( res6 . total , 2 ) ;
164+ // REMOVE_END
165+ // STEP_END
166+
167+ // STEP_START combined7
168+ const res7 = await client . ft . search ( 'idx:bicycle' ,
169+ '(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]' , {
170+ PARAMS : { query_vector : vector_query } ,
171+ DIALECT : 2
172+ }
173+ ) ;
174+ console . log ( res7 . total ) ; // >>> 2
175+ console . log ( res7 ) ; // >>>
176+ //{
177+ // total: 2,
178+ // documents: [
179+ // { id: 'bicycle:2', value: [Object: null prototype] },
180+ // { id: 'bicycle:9', value: [Object: null prototype] }
181+ // ]
182+ //}
183+ // REMOVE_START
184+ assert . strictEqual ( res7 . total , 2 ) ;
185+ // REMOVE_END
186+ // STEP_END
187+
188+ // REMOVE_START
189+ // destroy index and data
190+ await client . ft . dropIndex ( 'idx:bicycle' , { DD : true } ) ;
191+ await client . disconnect ( ) ;
192+ // REMOVE_END
0 commit comments