How to implement phrase match in redisearch?

I’m trying to implement a targeting feature on our AdServer (DSP). Currently our Ads are attached to a targeted keywords e.g. “Baseball caps” and all of these keywords are indexed in RediSearch. When a user on a publisher side searches for e.g. “Baseball caps for girls” then our adserver should return ads attach to keywords like the above example ad. but I have a problem figuring out how to write the queries:

FT.Search dummyIndex “@Keyword: Baseball caps for girls” wont return example ad with “Baseball caps” since the query string has extra words which does not exist withing the keyword.

using | (or) wont work either because FT.Search dummyIndex “@Keyword: (Baseball | girls)” will return the example ad but we should not since the query string does not have caps

is there any way I can achieve this using redisearch. please note that indexing the user query string rather than the keywords and search for the keywords within the index is not applicable.

I think the best solution for you is to go with Optional ~
See: Query syntax | Redis

Meaning in your case:

ft.search idx '@Keyword:~Baseball ~caps ~for ~girls' WITHSCORES

That will return the results that partially match your query and will give better score to those who better match.

127.0.0.1:6379> ft.search idx '@Keyword:~Baseball ~caps ~for ~girls' WITHSCORES
1) (integer) 1
2) "doc:1"
3) "3"
4) 1) "test"
   2) "Baseball caps"

127.0.0.1:6379> ft.search idx '@Keyword:~Baseball ~for ~girls' WITHSCORES
1) (integer) 1
2) "doc:1"
3) "2"
4) 1) "test"
   2) "Baseball caps"

127.0.0.1:6379> ft.search idx '@Keyword:~for ~girls' WITHSCORES
1) (integer) 1
2) "doc:1"
3) "0"
4) 1) "test"
   2) "Baseball caps"

Hello gkorland,

I thought about it but I am not sure how can I use the score to do post-filtering in a deterministic way to decide which doc to keep and what to exclude.

For example the second query "ft.search idx '@Keyword:~Baseball ~for ~girls' WITHSCORES" do return the doc “Baseball caps” but I should exclude it from the set of returned result since it does not contain the cap/s word.

Also, the example is a simplification of what I’m trying to accomplish. I am interested in applying different kinds of search/matching (Exact Match, Phrase Match, Broad Match)

e.g. in Phrase match I use slop and order and in my case, they should be applied to the query string rather than the document,
Phrase match examples:

Query string: “Baseball Caps for girls” should return Doc: “Baseball Caps” because all of the words from the doc exist in the QS and are in order and there are no words in between.

Query string: “Baseball small Caps for girls” should not return Doc: “Baseball Caps” because the QS contains extra words between the matching phrase from the doc.

Query string: “Caps Baseball for girls” should not return Doc: “Baseball Caps” because the order of the matching phrases in the QS has a different order than the ones from the Doc.

Regards

I’m not sure I get the full set of requirements here how do you decide to cut the query and why for girls is not included in the query. It seems like you’re trying to do semantic search and for that you might want to consider using Vector Similarity.

See demo: GitHub - RedisAI/vecsim-demo: Explore vector similarity in Redis

To make it simpler, what I’m trying to achieve is I want to look up the document within the query string not the other way around. So for a document to be returned, all of its phrases should exist within the QS.
Examples :
Redis document: “baseball caps” will return for all the following QSs :
"baseball caps for girls"
baseball red cap
“a cap for baseball
baseball player with a cap
The above examples are what we call broad-match. but in our system we have other matching types like phrase-match where I need to apply slop:0 and order:true at the QS not on the documents: Ex.
doc: “baseball caps” will return for all the following QSs in case of phrase-match :
"baseball caps for girls" … the slop:0 and order:true is respected within the QS
baseball cap” … the slop:0 and order:true is respected within the QS
“cool baseball caps” … the slop:0 and order:true is respected within the QS

baseball red caps” this will not return since the the slop:0 is not respected within the QS

127.0.0.1:6379> hset caps:1 title "baseball red caps"
(integer) 1
127.0.0.1:6379> hset caps:2 title "cool baseball caps"
(integer) 1
127.0.0.1:6379> hset caps:3 title "caps baseball"
(integer) 1
127.0.0.1:6379> ft.create capsIdx prefix 1 caps: schema title text
OK
127.0.0.1:6379> ft.search capsIdx "baseball caps"
1) (integer) 3
2) "caps:2"
3) 1) "title"
   2) "cool baseball caps"
4) "caps:3"
5) 1) "title"
   2) "caps baseball"
6) "caps:1"
7) 1) "title"
   2) "baseball red caps"
127.0.0.1:6379> ft.search capsIdx "(baseball caps)=>{$slop:0}"
1) (integer) 2
2) "caps:2"
3) 1) "title"
   2) "cool baseball caps"
4) "caps:3"
5) 1) "title"
   2) "caps baseball"
127.0.0.1:6379> ft.search capsIdx "(baseball caps)=>{$slop:0; $inorder:true}"
1) (integer) 1
2) "caps:2"
3) 1) "title"
   2) "cool baseball caps"

Hi k-jo
It seems that you did not understand that “baseball caps” is the indexed document and all the other sample strings are the query strings that could be fed to the search API.

:man_facepalming: Apologies, got it now, let me look into it