We are using Redisearch to insert structured JSON into Redis and searching by content to power autocomplete.
This is how our code looks like in Python:
rs = r.ft("a:a")
schema = (
TextField("$.key", as_name="key"),
NumericField("$.p", as_name="p"),
)
rs.create_index(
schema,
definition=IndexDefinition(
prefix=["a:"], index_type=IndexType.JSON
)
)
With this structure, we are able to insert keys and retrieve by values, like this:
testDic = "{'key': 'glooler-61245', 'val': 'sighgh', 'dom': 'test'}"
r.json().set("a:glooler-erree61245", Path.root_path(), ast.literal_eval(testDic))
prodDic = "{'key': 'booler-erree61245', 'val': 'brouhaha', 'dom': 'prod'}"
r.json().set("a:booler-erree61245", Path.root_path(), ast.literal_eval(prodDic))
rs.search(Query(f"glooler")) # returns only first entry
This works fine, as expected. But our requirement is that when we are in prod environment, our search should work only on the keys belonging to prod domain (the second key above). How do we specify that in our search query, or schema, so that the search doesn't even look at the data belonging to other domains? There is something like tag in Redis, unable to find out how to use it in our scenario, so a little help would be appreciated.
You are on to something using tags for search isolation.
First, set up a TagField
for the dom
field in the schema.
import redis
from redis.commands.json.path import Path
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
from redis.commands.search.field import NumericField, TagField, TextField
from redis.commands.search.query import Query
conn = redis.Redis(host="localhost", port=6379, db=0)
search = conn.ft("a:a")
schema = (
TextField("$.key", as_name="key"),
NumericField("$.p", as_name="p"),
TagField("$.dom", as_name="dom"),
)
search.dropindex(delete_documents=False)
index = search.create_index(
schema, definition=IndexDefinition(prefix=["a:"], index_type=IndexType.JSON)
)
testDic = {"key": "glooler-61245", "val": "sighgh", "dom": "test"}
conn.json().set("a:glooler-erree61245", Path.root_path(), testDic)
prodDict = {"key": "booler-erree61245", "val": "brouhaha", "dom": "prod"}
conn.json().set("a:booler-erree61245", Path.root_path(), prodDict)
Then tack on the tag in the query.
The following example looks up objects with dom
tag value of test
and matching *ool*
result = search.search(Query("*ool* @dom:{test}")) # returns only objects with test tag
print(result)
# Result{1 total, docs: [Document {'id': 'a:glooler-erree61245', 'payload': None, 'json': '{"key":"glooler-61245","val":"sighgh","dom":"test"}'}]}
The following example looks up objects with dom
tag value of prod
and matching *ool*
result = search.search(Query("*ool* @dom:{prod}")) # returns only objects with the prod tag
print(result)
# Result{1 total, docs: [Document {'id': 'a:booler-erree61245', 'payload': None, 'json': '{"key":"booler-erree61245","val":"brouhaha","dom":"prod"}'}]}
In order to sort the results by a priority
field in the document, configure in the index the field.
import redis
from redis.commands.json.path import Path
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
from redis.commands.search.field import NumericField, TagField, TextField
from redis.commands.search.query import Query
conn = redis.Redis(host="localhost", port=6379, db=0)
search = conn.ft("a:a")
schema = (
TextField("$.key", as_name="key"),
NumericField("$.p", as_name="p"),
TagField("$.dom", as_name="dom"),
NumericField("$.priority", as_name="priority", sortable=True)
)
search.dropindex(delete_documents=False)
index = search.create_index(
schema, definition=IndexDefinition(prefix=["a:"], index_type=IndexType.JSON)
)
prodDict1 = {"key": "booler-erree61245", "val": "brouhaha", "dom": "prod", "priority": 1}
prodDict2 = {"key": "booler-erree61246", "val": "brouhaha2", "dom": "prod", "priority": 2}
conn.json().set("a:booler-erree61245", Path.root_path(), prodDict1)
conn.json().set("a:booler-erree61246", Path.root_path(), prodDict2)
Then configure include sort_by
parameter in the search request as follows:
result = search.search(Query("*ool* @dom:{prod}").sort_by("priority", asc=True)) # returns only prod documents ordered by priority in ascending order.
print(result)