Skip to content

Commit e92df82

Browse files
authored
Extend support to all arguments of FT.SEARCH and FT.AGGREGATE commands (#3054)
* Extend support to all arguments of FT.SEARCH, FT.AGGREGATE commands. #3043 & #3044 * Fix documentTest serialize and multiplication cast to correct type * Addressing review comments in #3054 - Added individual tests for ft aggregate builder, Used Map instead of Param class for Key Value pair, Removed changes which were breaking changes (will create a separate PR for this) * Test cases changes - Added timeout arg testing and remove already existing dialect test case in SearchTest * Review changes for #3054 * Update timeout argument check in AggregationBuilder * Review changes - Moved the newly added arguments block above getArgs()
1 parent 13e3156 commit e92df82

File tree

6 files changed

+308
-1
lines changed

6 files changed

+308
-1
lines changed

src/main/java/redis/clients/jedis/search/Query.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ public HighlightTags(String open, String close) {
159159
private String _scorer = null;
160160
private Map<String, Object> _params = null;
161161
private int _dialect = 0;
162+
private int _slop = -1;
163+
private long _timeout = -1;
164+
private boolean _inOrder = false;
165+
private String _expander = null;
162166

163167
public Query() {
164168
this("*");
@@ -309,6 +313,25 @@ public void addParams(CommandArguments args) {
309313
args.add(SearchKeyword.DIALECT.getRaw());
310314
args.add(_dialect);
311315
}
316+
317+
if (_slop >= 0) {
318+
args.add(SearchKeyword.SLOP.getRaw());
319+
args.add(_slop);
320+
}
321+
322+
if (_timeout >= 0) {
323+
args.add(SearchKeyword.TIMEOUT.getRaw());
324+
args.add(_timeout);
325+
}
326+
327+
if (_inOrder) {
328+
args.add(SearchKeyword.INORDER.getRaw());
329+
}
330+
331+
if (_expander != null) {
332+
args.add(SearchKeyword.EXPANDER.getRaw());
333+
args.add(SafeEncoder.encode(_expander));
334+
}
312335
}
313336

314337
private static class DelayedRawable implements Rawable {
@@ -565,4 +588,47 @@ public Query dialect(int dialect) {
565588
_dialect = dialect;
566589
return this;
567590
}
591+
592+
/**
593+
* Set the slop to execute the query accordingly
594+
*
595+
* @param slop integer
596+
* @return the query object itself
597+
*/
598+
public Query slop(int slop) {
599+
_slop = slop;
600+
return this;
601+
}
602+
603+
/**
604+
* Set the timeout to execute the query accordingly
605+
*
606+
* @param timeout long
607+
* @return the query object itself
608+
*/
609+
public Query timeout(long timeout) {
610+
_timeout = timeout;
611+
return this;
612+
}
613+
614+
/**
615+
* Set the query terms appear in the same order in the document as in the query, regardless of the offsets between them
616+
*
617+
* @return the query object
618+
*/
619+
public Query setInOrder() {
620+
this._inOrder = true;
621+
return this;
622+
}
623+
624+
/**
625+
* Set the query to use a custom query expander instead of the stemmer
626+
*
627+
* @param field the expander field's name
628+
* @return the query object itself
629+
*/
630+
public Query setExpander(String field) {
631+
_expander = field;
632+
return this;
633+
}
568634
}

src/main/java/redis/clients/jedis/search/SearchProtocol.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public enum SearchKeyword implements Rawable {
5050
ASC, DESC, PAYLOAD, LIMIT, HIGHLIGHT, FIELDS, TAGS, SUMMARIZE, FRAGS, LEN, SEPARATOR, INKEYS,
5151
RETURN, /*NOSAVE, PARTIAL, REPLACE,*/ FILTER, GEOFILTER, INCR, MAX, FUZZY, DD, /*DELETE,*/ DEL,
5252
READ, COUNT, ADD, TEMPORARY, STOPWORDS, NOFREQS, NOFIELDS, NOOFFSETS, /*IF,*/ SET, GET, ON,
53-
ASYNC, PREFIX, LANGUAGE_FIELD, SCORE_FIELD, SCORE, PAYLOAD_FIELD, SCORER, PARAMS, DIALECT;
53+
ASYNC, PREFIX, LANGUAGE_FIELD, SCORE_FIELD, SCORE, PAYLOAD_FIELD, SCORER, PARAMS, DIALECT,
54+
SLOP, TIMEOUT, INORDER, EXPANDER;
5455

5556
private final byte[] raw;
5657

src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,38 @@ public AggregationBuilder cursor(int count, long maxIdle) {
128128
return this;
129129
}
130130

131+
public AggregationBuilder verbatim() {
132+
args.add("VERBATIM");
133+
return this;
134+
}
135+
136+
public AggregationBuilder timeout(long timeout) {
137+
if (timeout >= 0) {
138+
args.add("TIMEOUT");
139+
args.add(Long.toString(timeout));
140+
}
141+
return this;
142+
}
143+
144+
public AggregationBuilder params(Map<String, Object> params) {
145+
if (params.size() >= 1) {
146+
args.add("PARAMS");
147+
args.add(Integer.toString(params.size() * 2));
148+
for (Map.Entry<String, Object> entry : params.entrySet()) {
149+
args.add(entry.getKey());
150+
args.add(String.valueOf(entry.getValue()));
151+
}
152+
}
153+
154+
return this;
155+
}
156+
157+
public AggregationBuilder dialect(int dialect) {
158+
args.add("DIALECT");
159+
args.add(Integer.toString(dialect));
160+
return this;
161+
}
162+
131163
public List<String> getArgs() {
132164
return Collections.unmodifiableList(args);
133165
}

src/test/java/redis/clients/jedis/modules/search/AggregationBuilderTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,70 @@ public void testAggregations() {
8585
assertEquals(10, r2.getLong("sum"));
8686
}
8787

88+
@Test
89+
public void testAggregationBuilderVerbatim() {
90+
Schema sc = new Schema();
91+
sc.addSortableTextField("name", 1.0);
92+
client.ftCreate(index, IndexOptions.defaultOptions(), sc);
93+
addDocument(new Document("data1").set("name", "hello kitty"));
94+
95+
AggregationBuilder r = new AggregationBuilder("kitti");
96+
97+
AggregationResult res = client.ftAggregate(index, r);
98+
assertEquals(1, res.totalResults);
99+
100+
r = new AggregationBuilder("kitti")
101+
.verbatim();
102+
103+
res = client.ftAggregate(index, r);
104+
assertEquals(0, res.totalResults);
105+
}
106+
107+
@Test
108+
public void testAggregationBuilderTimeout() {
109+
Schema sc = new Schema();
110+
sc.addSortableTextField("name", 1.0);
111+
sc.addSortableNumericField("count");
112+
client.ftCreate(index, IndexOptions.defaultOptions(), sc);
113+
addDocument(new Document("data1").set("name", "abc").set("count", 10));
114+
addDocument(new Document("data2").set("name", "def").set("count", 5));
115+
addDocument(new Document("data3").set("name", "def").set("count", 25));
116+
117+
AggregationBuilder r = new AggregationBuilder()
118+
.groupBy("@name", Reducers.sum("@count").as("sum"))
119+
.timeout(5000);
120+
121+
AggregationResult res = client.ftAggregate(index, r);
122+
assertEquals(2, res.totalResults);
123+
}
124+
125+
@Test
126+
public void testAggregationBuilderParamsDialect() {
127+
Schema sc = new Schema();
128+
sc.addSortableTextField("name", 1.0);
129+
sc.addSortableNumericField("count");
130+
client.ftCreate(index, IndexOptions.defaultOptions(), sc);
131+
addDocument(new Document("data1").set("name", "abc").set("count", 10));
132+
addDocument(new Document("data2").set("name", "def").set("count", 5));
133+
addDocument(new Document("data3").set("name", "def").set("count", 25));
134+
135+
Map<String, Object> params = new HashMap<>();
136+
params.put("name", "abc");
137+
138+
AggregationBuilder r = new AggregationBuilder("$name")
139+
.groupBy("@name", Reducers.sum("@count").as("sum"))
140+
.params(params)
141+
.dialect(2); // From documentation - To use PARAMS, DIALECT must be set to 2
142+
143+
AggregationResult res = client.ftAggregate(index, r);
144+
assertEquals(1, res.totalResults);
145+
146+
Row r1 = res.getRow(0);
147+
assertNotNull(r1);
148+
assertEquals("abc", r1.getString("name"));
149+
assertEquals(10, r1.getLong("sum"));
150+
}
151+
88152
@Test
89153
public void testApplyAndFilterAggregations() {
90154
Schema sc = new Schema();

src/test/java/redis/clients/jedis/modules/search/JsonSearchTest.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,92 @@ public void parseJsonPartialWithFieldNames() {
230230
assertEquals("Dod", doc.get("last"));
231231
assertNull(doc.get("age"));
232232
}
233+
234+
@Test
235+
public void dialect() {
236+
Schema schema = new Schema()
237+
.addField(new TextField(FieldName.of("$.first").as("first")))
238+
.addField(new TextField(FieldName.of("$.last")))
239+
.addField(new Field(FieldName.of("$.age").as("age"), FieldType.NUMERIC));
240+
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.JSON);
241+
242+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions().setDefinition(rule), schema));
243+
244+
String id = "student:1111";
245+
JSONObject json = toJson("first", "Joe", "last", "Dod", "age", 18);
246+
setJson(id, json);
247+
248+
SearchResult sr = client.ftSearch(index, new Query().returnFields(FieldName.of("$.first").as("first"),
249+
FieldName.of("$.last").as("last"), FieldName.of("$.age")).dialect(1));
250+
assertEquals(1, sr.getTotalResults());
251+
assertEquals("Joe", sr.getDocuments().get(0).get("first"));
252+
assertEquals("Dod", sr.getDocuments().get(0).get("last"));
253+
}
254+
255+
@Test
256+
public void slop() {
257+
Schema schema = new Schema()
258+
.addField(new TextField(FieldName.of("$.first").as("first")))
259+
.addField(new TextField(FieldName.of("$.last")))
260+
.addField(new Field(FieldName.of("$.age").as("age"), FieldType.NUMERIC));
261+
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.JSON);
262+
263+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions().setDefinition(rule), schema));
264+
265+
String id = "student:1111";
266+
JSONObject json = toJson("first", "Joe is first ok", "last", "Dod will be first next", "age", 18);
267+
setJson(id, json);
268+
269+
SearchResult sr = client.ftSearch(index, new Query("Dod next").returnFields(FieldName.of("$.first").as("first"),
270+
FieldName.of("$.last").as("last"), FieldName.of("$.age")).slop(0));
271+
assertEquals(0, sr.getTotalResults());
272+
273+
sr = client.ftSearch(index, new Query("Dod next").returnFields(FieldName.of("$.first").as("first"),
274+
FieldName.of("$.last").as("last"), FieldName.of("$.age")).slop(1));
275+
assertEquals(1, sr.getTotalResults());
276+
}
277+
278+
@Test
279+
public void timeout() {
280+
Schema schema = new Schema()
281+
.addField(new TextField(FieldName.of("$.first").as("first")))
282+
.addField(new TextField(FieldName.of("$.last")))
283+
.addField(new Field(FieldName.of("$.age").as("age"), FieldType.NUMERIC));
284+
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.JSON);
285+
286+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions().setDefinition(rule), schema));
287+
288+
String id = "student:1111";
289+
JSONObject json = toJson("first", "Joe is first ok", "last", "Dod will be first next", "age", 18);
290+
setJson(id, json);
291+
292+
SearchResult sr = client.ftSearch(index, new Query("Dod next").returnFields(FieldName.of("$.first").as("first"),
293+
FieldName.of("$.last").as("last"), FieldName.of("$.age")).timeout(2000));
294+
assertEquals(1, sr.getTotalResults());
295+
}
296+
297+
@Test
298+
public void inOrder() {
299+
Schema schema = new Schema()
300+
.addField(new TextField(FieldName.of("$.first").as("first")))
301+
.addField(new TextField(FieldName.of("$.last")))
302+
.addField(new Field(FieldName.of("$.age").as("age"), FieldType.NUMERIC));
303+
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.JSON);
304+
305+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions().setDefinition(rule), schema));
306+
307+
String id = "student:1112";
308+
JSONObject json = toJson("first", "Joe is first ok", "last", "Dod will be first next", "age", 18);
309+
setJson(id, json);
310+
id = "student:1113";
311+
json = toJson("first", "Joe is first ok", "last", "Dod will be first next", "age", 18);
312+
setJson(id, json);
313+
id = "student:1111";
314+
json = toJson("first", "Joe is first ok", "last", "Dod will be first next", "age", 18);
315+
setJson(id, json);
316+
317+
SearchResult sr = client.ftSearch(index, new Query().setInOrder());
318+
assertEquals(3, sr.getTotalResults());
319+
assertEquals("student:1112", sr.getDocuments().get(0).getId());
320+
}
233321
}

src/test/java/redis/clients/jedis/modules/search/SearchTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,4 +1360,60 @@ public void synonym() {
13601360
expected.put("child", Arrays.asList(group1_str, group2_str));
13611361
assertEquals(expected, dump);
13621362
}
1363+
1364+
@Test
1365+
public void slop() {
1366+
Schema sc = new Schema().addTextField("field1", 1.0).addTextField("field2", 1.0);
1367+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc));
1368+
1369+
Map<String, Object> doc = new HashMap<>();
1370+
doc.put("field1", "ok hi jedis");
1371+
1372+
addDocument("doc1", doc);
1373+
1374+
SearchResult res = client.ftSearch(index, new Query("ok jedis").slop(0));
1375+
assertEquals(0, res.getTotalResults());
1376+
1377+
res = client.ftSearch(index, new Query("ok jedis").slop(1));
1378+
assertEquals(1, res.getTotalResults());
1379+
assertEquals("doc1", res.getDocuments().get(0).getId());
1380+
assertEquals("ok hi jedis", res.getDocuments().get(0).get("field1"));
1381+
}
1382+
1383+
@Test
1384+
public void timeout() {
1385+
Schema sc = new Schema().addTextField("field1", 1.0).addTextField("field2", 1.0);
1386+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc));
1387+
1388+
Map<String, Object> doc = new HashMap<>();
1389+
doc.put("field1", "value");
1390+
doc.put("field2", "not");
1391+
1392+
addDocument("doc1", doc);
1393+
1394+
SearchResult res = client.ftSearch(index, new Query("value").timeout(1000));
1395+
assertEquals(1, res.getTotalResults());
1396+
assertEquals("doc1", res.getDocuments().get(0).getId());
1397+
assertEquals("value", res.getDocuments().get(0).get("field1"));
1398+
assertEquals("not", res.getDocuments().get(0).get("field2"));
1399+
}
1400+
1401+
@Test
1402+
public void inOrder() {
1403+
Schema sc = new Schema().addTextField("field1", 1.0).addTextField("field2", 1.0);
1404+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc));
1405+
1406+
Map<String, Object> doc = new HashMap<>();
1407+
doc.put("field1", "value");
1408+
doc.put("field2", "not");
1409+
1410+
addDocument("doc2", doc);
1411+
addDocument("doc1", doc);
1412+
1413+
SearchResult res = client.ftSearch(index, new Query("value").setInOrder());
1414+
assertEquals(2, res.getTotalResults());
1415+
assertEquals("doc2", res.getDocuments().get(0).getId());
1416+
assertEquals("value", res.getDocuments().get(0).get("field1"));
1417+
assertEquals("not", res.getDocuments().get(0).get("field2"));
1418+
}
13631419
}

0 commit comments

Comments
 (0)