Skip to content

Support json index type #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Jun 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a5ec27c
fix bug
AvitalFineRedis May 13, 2021
bebef6e
Update client.py
AvitalFineRedis May 13, 2021
c8fbd56
Update client.py
AvitalFineRedis May 13, 2021
1d3b97a
set to True
AvitalFineRedis May 13, 2021
677c53e
set to False
AvitalFineRedis May 13, 2021
30050b9
change to parameter
AvitalFineRedis May 13, 2021
a353b70
Merge branch 'master' into support_JSON_index_type
AvitalFineRedis Jun 6, 2021
0ea89f0
add index_type parameter
AvitalFineRedis Jun 6, 2021
439b92c
change yaml to run on redismod:latest
AvitalFineRedis Jun 8, 2021
4e9695f
Update client.py
AvitalFineRedis Jun 10, 2021
0d52065
Update test.py
AvitalFineRedis Jun 10, 2021
da5f582
Added testJSONIndex
rafie Jun 15, 2021
aecc3c5
add rejson
AvitalFineRedis Jun 15, 2021
3373adf
Remove comments
rafie Jun 15, 2021
ac1bcea
test
AvitalFineRedis Jun 15, 2021
f5ac2e0
test
AvitalFineRedis Jun 15, 2021
f0fa493
Merge branch 'support_JSON_index_type' of ssh://github.com/RediSearch…
AvitalFineRedis Jun 15, 2021
0aff5d8
fix comments
AvitalFineRedis Jun 15, 2021
3589bce
fix comments
AvitalFineRedis Jun 15, 2021
3604ffe
Merge branch 'support_JSON_index_type' of ssh://github.com/RediSearch…
AvitalFineRedis Jun 15, 2021
ac49e6a
Update client.py
AvitalFineRedis Jun 17, 2021
a666419
add test to incorrect index_type variable
AvitalFineRedis Jun 17, 2021
be77304
test the returned value
AvitalFineRedis Jun 17, 2021
409f527
remove class variables
AvitalFineRedis Jun 17, 2021
4ae198a
add json property to document
AvitalFineRedis Jun 17, 2021
09311b1
add json property to document
AvitalFineRedis Jun 17, 2021
f11c201
remove import
AvitalFineRedis Jun 17, 2021
39850dd
Merge branch 'support_JSON_index_type' of ssh://github.com/RediSearch…
AvitalFineRedis Jun 17, 2021
7bccd73
remove import
AvitalFineRedis Jun 17, 2021
12352ed
Update result.py
AvitalFineRedis Jun 17, 2021
14850e1
remove import
AvitalFineRedis Jun 17, 2021
b597000
Merge branch 'support_JSON_index_type' of ssh://github.com/RediSearch…
AvitalFineRedis Jun 17, 2021
236dfd6
Add Docstring to IndexType Enum
AvitalFineRedis Jun 21, 2021
b2190c3
Merge branch 'master' into support_JSON_index_type
AvitalFineRedis Jun 21, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
default: latest
docker:
- image: circleci/python:<<parameters.python_version >>
- image: redislabs/redisearch:edge
- image: redislabs/redismod:edge
steps:
- build_and_test

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ python = ">=2.7,<=2.9.0 || >= 3.5.0"
redis = "^3.5.3"
six = "^1.16.0"
rmtest = {git = "https://github.com/RedisLabs/rmtest"}
rejson = "^0.5.4"
hiredis = [
{version = "1.1.0", python = "~2.7"},
{version = "^2.0.0", python = "^3.6"},
Expand Down
44 changes: 24 additions & 20 deletions redisearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .query import Query
from ._util import to_string
from .aggregation import AggregateRequest, AggregateResult, Cursor
from enum import Enum


class Field(object):
Expand Down Expand Up @@ -87,53 +88,56 @@ def __init__(self, name, separator=',', **kwargs):
Field.__init__(self, name, args=[Field.TAG, self.SEPARATOR, separator], **kwargs)


class IndexType(Enum):
"""
Enum of the currently supported index types.
"""
HASH = 1
JSON = 2

class IndexDefinition(object):
"""
IndexDefinition is used to define a index definition for automatic indexing on Hash update
IndexDefinition is used to define a index definition for automatic indexing on Hash or Json update.
"""

ON = 'ON'
HASH = 'HASH'
PREFIX = 'PREFIX'
FILTER = 'FILTER'
LANGUAGE_FIELD = 'LANGUAGE_FIELD'
LANGUAGE = 'LANGUAGE'
SCORE_FIELD = 'SCORE_FIELD'
SCORE = 'SCORE'
PAYLOAD_FIELD = 'PAYLOAD_FIELD'

def __init__(self, prefix=[], filter=None, language_field=None, language=None, score_field=None, score=1.0, payload_field=None):
def __init__(self, prefix=[], filter=None, language_field=None, language=None, score_field=None, score=1.0, payload_field=None, index_type=None):
args = []

args = [self.ON, self.HASH]
if index_type is IndexType.HASH:
args.extend(['ON', 'HASH'])
elif index_type is IndexType.JSON:
args.extend(['ON', 'JSON'])
elif index_type is not None:
raise RuntimeError("index_type must be one of {}".format(list(IndexType)))

if len(prefix) > 0:
args.append(self.PREFIX)
args.append('PREFIX')
args.append(len(prefix))
for p in prefix:
args.append(p)

if filter is not None:
args.append(self.FILTER)
args.append('FILTER')
args.append(filter)

if language_field is not None:
args.append(self.LANGUAGE_FIELD)
args.append('LANGUAGE_FIELD')
args.append(language_field)

if language is not None:
args.append(self.LANGUAGE)
args.append('LANGUAGE')
args.append(language)

if score_field is not None:
args.append(self.SCORE_FIELD)
args.append('SCORE_FIELD')
args.append(score_field)

if score is not None:
args.append(self.SCORE)
args.append('SCORE')
args.append(score)

if payload_field is not None:
args.append(self.PAYLOAD_FIELD)
args.append('PAYLOAD_FIELD')
args.append(payload_field)

self.args = args
Expand Down
11 changes: 9 additions & 2 deletions redisearch/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
from .document import Document
from ._util import to_string



class Result(object):
"""
Represents the result of a search query, and has an array of Document objects
"""

def __init__(self, res, hascontent, duration=0, has_payload = False, with_scores = False):
def __init__(self, res, hascontent, duration=0, has_payload=False, with_scores=False):
"""
- **snippets**: An optional dictionary of the form {field: snippet_size} for snippet formatting
"""
Expand Down Expand Up @@ -45,9 +47,14 @@ def __init__(self, res, hascontent, duration=0, has_payload = False, with_scores
except KeyError:
pass

try:
fields['json'] = fields['$']
del fields['$']
except KeyError:
pass

doc = Document(id, score=score, payload=payload, **fields) if with_scores else Document(id, payload=payload, **fields)
self.docs.append(doc)

def __repr__(self):

return 'Result{%d total, docs: %s}' % (self.total, self.docs)
80 changes: 73 additions & 7 deletions test/test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import json
import os, sys


sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from rmtest import ModuleTestCase
Expand All @@ -12,8 +15,10 @@
import six

from redisearch import *
from redisearch.client import IndexType
import redisearch.aggregation as aggregations
import redisearch.reducers as reducers
import rejson

WILL_PLAY_TEXT = os.path.abspath(os.path.dirname(__file__)) + '/will_play_text.csv.bz2'

Expand Down Expand Up @@ -487,6 +492,7 @@ def testAutoComplete(self):
def testNoIndex(self):
# Creating a client with a given index name
client = self.getCleanClient('idx')
client.redis.flushdb()

client.create_index(
(TextField('field'),
Expand Down Expand Up @@ -946,7 +952,10 @@ def testAggregations(self):
self.assertEqual('RediSearch', res[23])
self.assertEqual(2, len(res[25]))

def testIndexDefiniontion(self):
def testIndexDefinition(self):
"""
Create definition and test its args
"""
conn = self.redis()

with conn as r:
Expand All @@ -955,19 +964,24 @@ def testIndexDefiniontion(self):
return
client = Client('test', port=conn.port)

self.assertRaises(RuntimeError, IndexDefinition, prefix=['hset:', 'henry'], index_type='json')

definition = IndexDefinition(prefix=['hset:', 'henry'],
filter='@f1==32', language='English', language_field='play',
score_field='chapter', score=0.5, payload_field='txt' )
score_field='chapter', score=0.5, payload_field='txt', index_type=IndexType.JSON)

self.assertEqual(['ON','HASH', 'PREFIX',2,'hset:','henry',
'FILTER','@f1==32','LANGUAGE_FIELD','play','LANGUAGE','English',
'SCORE_FIELD','chapter','SCORE',0.5,'PAYLOAD_FIELD','txt'],
self.assertEqual(['ON', 'JSON', 'PREFIX', 2, 'hset:', 'henry',
'FILTER', '@f1==32', 'LANGUAGE_FIELD', 'play', 'LANGUAGE', 'English',
'SCORE_FIELD', 'chapter', 'SCORE', 0.5, 'PAYLOAD_FIELD', 'txt'],
definition.args)

self.createIndex(client, num_docs=500, definition=definition)


def testCreateClientDefiniontion(self):
def testCreateClientDefinition(self):
"""
Create definition with no index type provided,
and use hset to test the client definition (the default is HASH).
"""
conn = self.redis()

with conn as r:
Expand All @@ -987,5 +1001,57 @@ def testCreateClientDefiniontion(self):
info = client.info()
self.assertEqual(495, int(info['num_docs']))

def testCreateClientDefinitionHash(self):
"""
Create definition with IndexType.HASH as index type (ON HASH),
and use hset to test the client definition.
"""
conn = self.redis()

with conn as r:
r.flushdb()
if not check_version(r, 20000):
return
client = Client('test', port=conn.port)

definition = IndexDefinition(prefix=['hset:', 'henry'], index_type=IndexType.HASH)
self.createIndex(client, num_docs=500, definition=definition)

info = client.info()
self.assertEqual(494, int(info['num_docs']))

r.hset('hset:1', 'f1', 'v1');

info = client.info()
self.assertEqual(495, int(info['num_docs']))

def testCreateClientDefinitionJson(self):
"""
Create definition with IndexType.JSON as index type (ON JSON),
and use json client to test it.
"""
conn = self.redis()

with conn as r:
r.flushdb()
if not check_version(r, 20200):
return

client = Client('json1', port=conn.port)

definition = IndexDefinition(prefix=['king:'], index_type=IndexType.JSON)
client.create_index((TextField('$.name'),), definition=definition)

rj = rejson.Client(host='localhost', port=conn.port, decode_responses=True)
rj.jsonset('king:1', rejson.Path.rootPath(), {'name': 'henry'})
rj.jsonset('king:2', rejson.Path.rootPath(), {'name': 'james'})

res = client.search('henry')
self.assertEqual(res.docs[0].id, 'king:1')
self.assertIsNone(res.docs[0].payload)
self.assertEqual(res.docs[0].json, '{"name":"henry"}')
self.assertEqual(res.total, 1)


if __name__ == '__main__':
unittest.main()