Skip to content

Commit 5fa461e

Browse files
DvirDukhansazzad16
andauthored
Support RediSearch DIALECT (#2960)
* added dialect * fixed test default dialect * added javadoc * format codes Co-authored-by: M Sazzadul Hoque <[email protected]>
1 parent 83af8c1 commit 5fa461e

File tree

3 files changed

+152
-9
lines changed

3 files changed

+152
-9
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ public HighlightTags(String open, String close) {
158158
private boolean wantsSummarize = false;
159159
private String _scorer = null;
160160
private Map<String, Object> _params = null;
161+
private int _dialect = 0;
161162

162163
public Query() {
163164
this("*");
@@ -303,6 +304,11 @@ public void addParams(CommandArguments args) {
303304
args.add(entry.getValue());
304305
}
305306
}
307+
308+
if (_dialect != 0) {
309+
args.add(SearchKeyword.DIALECT.getRaw());
310+
args.add(_dialect);
311+
}
306312
}
307313

308314
private static class DelayedRawable implements Rawable {
@@ -548,4 +554,15 @@ public Query addParam(String name, Object value) {
548554
_params.put(name, value);
549555
return this;
550556
}
557+
558+
/**
559+
* Set the dialect version to execute the query accordingly
560+
*
561+
* @param dialect integer
562+
* @return the query object itself
563+
*/
564+
public Query dialect(int dialect) {
565+
_dialect = dialect;
566+
return this;
567+
}
551568
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public enum SearchKeyword implements Rawable {
4646
ASC, DESC, PAYLOAD, LIMIT, HIGHLIGHT, FIELDS, TAGS, SUMMARIZE, FRAGS, LEN, SEPARATOR, INKEYS,
4747
RETURN, /*NOSAVE, PARTIAL, REPLACE,*/ FILTER, GEOFILTER, INCR, MAX, FUZZY, DD, /*DELETE,*/ DEL,
4848
READ, COUNT, ADD, TEMPORARY, STOPWORDS, NOFREQS, NOFIELDS, NOOFFSETS, /*IF,*/ SET, GET, ON,
49-
ASYNC, PREFIX, LANGUAGE_FIELD, SCORE_FIELD, SCORE, PAYLOAD_FIELD, SCORER, PARAMS;
49+
ASYNC, PREFIX, LANGUAGE_FIELD, SCORE_FIELD, SCORE, PAYLOAD_FIELD, SCORER, PARAMS, DIALECT;
5050

5151
private final byte[] raw;
5252

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

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package redis.clients.jedis.modules.search;
22

3+
import static java.util.Collections.singletonMap;
34
import static org.junit.Assert.*;
45
import static redis.clients.jedis.search.RediSearchUtil.toStringMap;
56

@@ -451,10 +452,11 @@ public void testHNSWVVectorSimilarity() {
451452
client.hset("b", "v", "aaaabaaa");
452453
client.hset("c", "v", "aaaaabaa");
453454

454-
Query query = new Query("*=>[KNN 2 @v $vec]")
455+
Query query = new Query("*=>[KNN 2 @v $vec]")
455456
.addParam("vec", "aaaaaaaa")
456457
.setSortBy("__v_score", true)
457-
.returnFields("__v_score");
458+
.returnFields("__v_score")
459+
.dialect(2);
458460
Document doc1 = client.ftSearch(index, query).getDocuments().get(0);
459461
assertEquals("a", doc1.getId());
460462
assertEquals("0", doc1.get("__v_score"));
@@ -474,15 +476,139 @@ public void testFlatVectorSimilarity() {
474476
client.hset("b", "v", "aaaabaaa");
475477
client.hset("c", "v", "aaaaabaa");
476478

477-
Query query = new Query("*=>[KNN 2 @v $vec]")
479+
Query query = new Query("*=>[KNN 2 @v $vec]")
478480
.addParam("vec", "aaaaaaaa")
479481
.setSortBy("__v_score", true)
480-
.returnFields("__v_score");
482+
.returnFields("__v_score")
483+
.dialect(2);
481484
Document doc1 = client.ftSearch(index, query).getDocuments().get(0);
482485
assertEquals("a", doc1.getId());
483486
assertEquals("0", doc1.get("__v_score"));
484487
}
485488

489+
@Test
490+
public void testDialectConfig() {
491+
// confirm default
492+
assertEquals(singletonMap("DEFAULT_DIALECT", "1"), client.ftConfigGet("DEFAULT_DIALECT"));
493+
494+
assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "2"));
495+
assertEquals(singletonMap("DEFAULT_DIALECT", "2"), client.ftConfigGet("DEFAULT_DIALECT"));
496+
497+
try {
498+
client.ftConfigSet("DEFAULT_DIALECT", "0");
499+
fail();
500+
} catch (JedisDataException ex) {
501+
}
502+
503+
try {
504+
client.ftConfigSet("DEFAULT_DIALECT", "3");
505+
fail();
506+
} catch (JedisDataException ex) {
507+
}
508+
509+
// Restore to default
510+
assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "1"));
511+
}
512+
513+
@Test
514+
public void testDialectsWithFTExplain() throws Exception {
515+
Map<String, Object> attr = new HashMap<>();
516+
attr.put("TYPE", "FLOAT32");
517+
attr.put("DIM", 2);
518+
attr.put("DISTANCE_METRIC", "L2");
519+
520+
Schema sc = new Schema()
521+
.addFlatVectorField("v", attr)
522+
.addTagField("title")
523+
.addTextField("t1", 1.0)
524+
.addTextField("t2", 1.0)
525+
.addNumericField("num");
526+
assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc));
527+
528+
client.hset("1", "t1", "hello");
529+
530+
String q = "(*)";
531+
Query query = new Query(q).dialect(1);
532+
try {
533+
client.ftExplain(index, query);
534+
fail();
535+
} catch (JedisDataException e) {
536+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
537+
}
538+
query = new Query(q).dialect(2);
539+
assertTrue("Should contain 'WILDCARD'", client.ftExplain(index, query).contains("WILDCARD"));
540+
541+
q = "$hello";
542+
query = new Query(q).dialect(1);
543+
try {
544+
client.ftExplain(index, query);
545+
fail();
546+
} catch (JedisDataException e) {
547+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
548+
}
549+
query = new Query(q).dialect(2).addParam("hello", "hello");
550+
assertTrue("Should contain 'UNION {\n hello\n +hello(expanded)\n}\n'",
551+
client.ftExplain(index, query).contains("UNION {\n hello\n +hello(expanded)\n}\n"));
552+
553+
q = "@title:(@num:[0 10])";
554+
query = new Query(q).dialect(1);
555+
assertTrue("Should contain 'NUMERIC {0.000000 <= @num <= 10.000000}'",
556+
client.ftExplain(index, query).contains("NUMERIC {0.000000 <= @num <= 10.000000}"));
557+
query = new Query(q).dialect(2);
558+
try {
559+
client.ftExplain(index, query);
560+
fail();
561+
} catch (JedisDataException e) {
562+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
563+
}
564+
565+
q = "@t1:@t2:@t3:hello";
566+
query = new Query(q).dialect(1);
567+
assertTrue("Should contain '@NULL:UNION {\n @NULL:hello\n @NULL:+hello(expanded)\n}\n'",
568+
client.ftExplain(index, query).contains("@NULL:UNION {\n @NULL:hello\n @NULL:+hello(expanded)\n}\n"));
569+
query = new Query(q).dialect(2);
570+
try {
571+
client.ftExplain(index, query);
572+
fail();
573+
} catch (JedisDataException e) {
574+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
575+
}
576+
577+
q = "@title:{foo}}}}}";
578+
query = new Query(q).dialect(1);
579+
assertTrue("Should contain 'TAG:@title {\n foo\n}\n'",
580+
client.ftExplain(index, query).contains("TAG:@title {\n foo\n}\n"));
581+
query = new Query(q).dialect(2);
582+
try {
583+
client.ftExplain(index, query);
584+
fail();
585+
} catch (JedisDataException e) {
586+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
587+
}
588+
589+
q = "*=>[KNN 10 @v $BLOB]";
590+
query = new Query(q).addParam("BLOB", "aaaa").dialect(1);
591+
try {
592+
client.ftExplain(index, query);
593+
fail();
594+
} catch (JedisDataException e) {
595+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
596+
}
597+
query = new Query(q).addParam("BLOB", "aaaa").dialect(2);
598+
assertTrue("Should contain '{K=10 nearest vector'", client.ftExplain(index, query).contains("{K=10 nearest vector"));
599+
600+
q = "*=>[knn $K @vec_field $BLOB as score]";
601+
query = new Query(q).addParam("BLOB", "aaaa").addParam("K", "10").dialect(1);
602+
try {
603+
client.ftExplain(index, query);
604+
fail();
605+
} catch (JedisDataException e) {
606+
assertTrue("Should contain 'Syntax error'", e.getMessage().contains("Syntax error"));
607+
}
608+
query = new Query(q).addParam("BLOB", "aaaa").addParam("K", "10").dialect(2);
609+
assertTrue("Should contain '{K=10 nearest vector'", client.ftExplain(index, query).contains("{K=10 nearest vector"));
610+
}
611+
486612
@Test
487613
public void testQueryParams() {
488614
Schema sc = new Schema().addNumericField("numval");
@@ -492,7 +618,7 @@ public void testQueryParams() {
492618
client.hset("2", "numval", "2");
493619
client.hset("3", "numval", "3");
494620

495-
Query query = new Query("@numval:[$min $max]").addParam("min", 1).addParam("max", 2);
621+
Query query = new Query("@numval:[$min $max]").addParam("min", 1).addParam("max", 2).dialect(2);
496622
assertEquals(2, client.ftSearch(index, query).getTotalResults());
497623
}
498624

@@ -1218,8 +1344,8 @@ public void returnWithFieldNames() throws Exception {
12181344
addDocument("doc", map);
12191345

12201346
// Query
1221-
SearchResult res = client.ftSearch(index, new Query()
1222-
.returnFields(FieldName.of("a"), FieldName.of("b").as("d")));
1347+
SearchResult res = client.ftSearch(index,
1348+
new Query().returnFields(FieldName.of("a"), FieldName.of("b").as("d")));
12231349
assertEquals(1, res.getTotalResults());
12241350
Document doc = res.getDocuments().get(0);
12251351
assertEquals("value1", doc.get("a"));
@@ -1285,7 +1411,7 @@ public void config() throws Exception {
12851411
@Test
12861412
public void configOnTimeout() throws Exception {
12871413
assertEquals("OK", client.ftConfigSet("ON_TIMEOUT", "fail"));
1288-
assertEquals(Collections.singletonMap("ON_TIMEOUT", "fail"), client.ftConfigGet("ON_TIMEOUT"));
1414+
assertEquals(singletonMap("ON_TIMEOUT", "fail"), client.ftConfigGet("ON_TIMEOUT"));
12891415

12901416
try {
12911417
client.ftConfigSet("ON_TIMEOUT", "null");

0 commit comments

Comments
 (0)