1+ <?php
2+
3+ namespace Vladvildanov \PredisVl \Feature \Index ;
4+
5+ use Vladvildanov \PredisVl \Feature \FeatureTestCase ;
6+ use Predis \Client ;
7+ use Vladvildanov \PredisVl \Index \SearchIndex ;
8+ use Vladvildanov \PredisVl \VectorHelper ;
9+
10+ class SearchIndexTest extends FeatureTestCase
11+ {
12+ /**
13+ * @var Client
14+ */
15+ private Client $ client ;
16+
17+ /**
18+ * @var array
19+ */
20+ private array $ hashSchema ;
21+
22+ /**
23+ * @var array
24+ */
25+ private array $ jsonSchema ;
26+
27+ protected function setUp (): void
28+ {
29+ $ this ->client = $ this ->getClient ();
30+ $ this ->hashSchema = [
31+ 'index ' => [
32+ 'name ' => 'foobar ' ,
33+ 'prefix ' => 'foo: ' ,
34+ ],
35+ 'fields ' => [
36+ 'id ' => [
37+ 'type ' => 'text ' ,
38+ 'alias ' => 'foo ' ,
39+ ],
40+ 'count ' => [
41+ 'type ' => 'numeric ' ,
42+ ],
43+ 'id_embeddings ' => [
44+ 'type ' => 'vector ' ,
45+ 'algorithm ' => 'flat ' ,
46+ 'dims ' => 3 ,
47+ 'datatype ' => 'float32 ' ,
48+ 'distance_metric ' => 'cosine ' ,
49+ ]
50+ ]
51+ ];
52+ $ this ->jsonSchema = [
53+ 'index ' => [
54+ 'name ' => 'foobar ' ,
55+ 'prefix ' => 'foo: ' ,
56+ 'storage_type ' => 'json '
57+ ],
58+ 'fields ' => [
59+ '$.id ' => [
60+ 'type ' => 'text ' ,
61+ 'alias ' => 'foo ' ,
62+ ],
63+ '$.count ' => [
64+ 'type ' => 'numeric ' ,
65+ ],
66+ '$.id_embeddings ' => [
67+ 'type ' => 'vector ' ,
68+ 'algorithm ' => 'flat ' ,
69+ 'dims ' => 3 ,
70+ 'datatype ' => 'float32 ' ,
71+ 'distance_metric ' => 'cosine ' ,
72+ ]
73+ ]
74+ ];
75+ }
76+
77+ /**
78+ * @return void
79+ */
80+ public function testCreatesHashIndexWithMultipleFields (): void
81+ {
82+ $ index = new SearchIndex ($ this ->client , $ this ->hashSchema );
83+ $ this ->assertEquals ('OK ' , $ index ->create ());
84+
85+ $ indexInfo = $ this ->client ->ftinfo ($ this ->hashSchema ['index ' ]['name ' ]);
86+
87+ $ this ->assertEquals ('foobar ' , $ indexInfo [1 ]);
88+ $ this ->assertEquals ('HASH ' , $ indexInfo [5 ][1 ]);
89+ $ this ->assertEquals ('foo: ' , $ indexInfo [5 ][3 ][0 ]);
90+ $ this ->assertEquals ('foo ' , $ indexInfo [7 ][0 ][3 ]);
91+ $ this ->assertEquals ('TEXT ' , $ indexInfo [7 ][0 ][5 ]);
92+ $ this ->assertEquals ('NUMERIC ' , $ indexInfo [7 ][1 ][5 ]);
93+ $ this ->assertEquals ('VECTOR ' , $ indexInfo [7 ][2 ][5 ]);
94+
95+ $ this ->assertEquals (
96+ 'OK ' ,
97+ $ index ->load ('foo:1 ' , ['id ' => '1 ' , 'count ' => 10 , 'id_embeddings ' => VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ])])
98+ );
99+
100+ $ searchResult = $ this ->client ->ftsearch ($ this ->hashSchema ['index ' ]['name ' ], '* ' );
101+
102+ $ this ->assertSame ('foo:1 ' , $ searchResult [1 ]);
103+ $ this ->assertSame ('1 ' , $ searchResult [2 ][1 ]);
104+ $ this ->assertSame ('10 ' , $ searchResult [2 ][3 ]);
105+ $ this ->assertSame (VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ]), $ searchResult [2 ][5 ]);
106+ }
107+
108+ /**
109+ * @return void
110+ */
111+ public function testCreatesJsonIndexWithMultipleFields (): void
112+ {
113+ $ index = new SearchIndex ($ this ->client , $ this ->jsonSchema );
114+ $ this ->assertEquals ('OK ' , $ index ->create ());
115+
116+ $ indexInfo = $ this ->client ->ftinfo ($ this ->jsonSchema ['index ' ]['name ' ]);
117+
118+ $ this ->assertEquals ('foobar ' , $ indexInfo [1 ]);
119+ $ this ->assertEquals ('JSON ' , $ indexInfo [5 ][1 ]);
120+ $ this ->assertEquals ('foo: ' , $ indexInfo [5 ][3 ][0 ]);
121+ $ this ->assertEquals ('foo ' , $ indexInfo [7 ][0 ][3 ]);
122+ $ this ->assertEquals ('TEXT ' , $ indexInfo [7 ][0 ][5 ]);
123+ $ this ->assertEquals ('NUMERIC ' , $ indexInfo [7 ][1 ][5 ]);
124+ $ this ->assertEquals ('VECTOR ' , $ indexInfo [7 ][2 ][5 ]);
125+
126+ $ this ->assertEquals (
127+ 'OK ' ,
128+ $ index ->load ('foo:1 ' , '{"id":"1","count":10,"id_embeddings":[0.000001, 0.000002, 0.000003]} ' )
129+ );
130+
131+ $ searchResult = $ this ->client ->ftsearch ($ this ->jsonSchema ['index ' ]['name ' ], '* ' );
132+
133+ $ this ->assertSame ('foo:1 ' , $ searchResult [1 ]);
134+ $ this ->assertSame ('{"id":"1","count":10,"id_embeddings":[1e-6,2e-6,3e-6]} ' , $ searchResult [2 ][1 ]);
135+ }
136+
137+ /**
138+ * @return void
139+ */
140+ public function testCreatesHashIndexWithOverride (): void
141+ {
142+ $ index = new SearchIndex ($ this ->client , $ this ->hashSchema );
143+ $ this ->assertEquals ('OK ' , $ index ->create ());
144+
145+ $ indexInfo = $ this ->client ->ftinfo ($ this ->hashSchema ['index ' ]['name ' ]);
146+
147+ $ this ->assertEquals ('foobar ' , $ indexInfo [1 ]);
148+ $ this ->assertEquals ('HASH ' , $ indexInfo [5 ][1 ]);
149+ $ this ->assertEquals ('foo: ' , $ indexInfo [5 ][3 ][0 ]);
150+ $ this ->assertEquals ('foo ' , $ indexInfo [7 ][0 ][3 ]);
151+ $ this ->assertEquals ('TEXT ' , $ indexInfo [7 ][0 ][5 ]);
152+ $ this ->assertEquals ('NUMERIC ' , $ indexInfo [7 ][1 ][5 ]);
153+ $ this ->assertEquals ('VECTOR ' , $ indexInfo [7 ][2 ][5 ]);
154+
155+ $ this ->assertEquals ('OK ' , $ index ->create (true ));
156+
157+ $ this ->assertEquals (
158+ 'OK ' ,
159+ $ index ->load ('foo:1 ' , ['id ' => '1 ' , 'count ' => 10 , 'id_embeddings ' => VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ])])
160+ );
161+
162+ $ searchResult = $ this ->client ->ftsearch ($ this ->hashSchema ['index ' ]['name ' ], '* ' );
163+
164+ $ this ->assertSame ('foo:1 ' , $ searchResult [1 ]);
165+ $ this ->assertSame ('1 ' , $ searchResult [2 ][1 ]);
166+ $ this ->assertSame ('10 ' , $ searchResult [2 ][3 ]);
167+ $ this ->assertSame (VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ]), $ searchResult [2 ][5 ]);
168+ }
169+
170+ /**
171+ * @return void
172+ */
173+ public function testFetchHashData (): void
174+ {
175+ $ index = new SearchIndex ($ this ->client , $ this ->hashSchema );
176+ $ this ->assertEquals ('OK ' , $ index ->create ());
177+
178+ $ this ->assertEquals (
179+ 'OK ' ,
180+ $ index ->load ('foo:1 ' , ['id ' => '1 ' , 'count ' => 10 , 'id_embeddings ' => VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ])])
181+ );
182+
183+ $ this ->assertEquals (
184+ ['id ' => '1 ' , 'count ' => 10 , 'id_embeddings ' => VectorHelper::toBytes ([0.000001 , 0.000002 , 0.000003 ])],
185+ $ index ->fetch ('1 ' ));
186+ }
187+
188+ /**
189+ * @return void
190+ */
191+ public function testFetchJsonData (): void
192+ {
193+ $ index = new SearchIndex ($ this ->client , $ this ->jsonSchema );
194+ $ this ->assertEquals ('OK ' , $ index ->create ());
195+
196+ $ this ->assertEquals (
197+ 'OK ' ,
198+ $ index ->load ('foo:1 ' , '{"id":"1","count":10,"id_embeddings":[0.000001, 0.000002, 0.000003]} ' )
199+ );
200+
201+ $ this ->assertEquals (
202+ '{"id":"1","count":10,"id_embeddings":[1e-6,2e-6,3e-6]} ' ,
203+ $ index ->fetch ('1 ' ));
204+ }
205+ }
0 commit comments