Search code examples
pythonredisredis-pyredisearch

Redisearch Python simple example


The documentation for Redisearch module is not the best at the moment. Can someone please give short examples that will answer these questions? Thank you

  1. How to use Redisearch module with redis-py?
  2. How to sort by multiple fields?
  3. How to paginate results?

Solution

  • Posting the answer. I spent quite some time to figure all these out, so hopefully it will save time for some of you. Redisearch is truly an amazing technology that deserves to be used by many.

    First and foremost you have to create an index to use redisearch:

    from redis.commands.search.query import Query
    from redis.commands.search.field import TextField, NumericField
    from redis.commands.search.indexDefinition import IndexDefinition, IndexType
    from redis.commands.search.aggregation import AggregateRequest, Asc, Desc
    
    import redis
    
    client = redis.Redis(
            host=redis_host,
            port=redis_port,
            password=redis_password,
            decode_responses=True,
        )
    
    index_name = 'idx:flowers'
    index = client.ft(index_name)
    
    #  check if index exists if not then create
    try:
        index.info()
    except:
        schema = (
            TextField('name', weight=0.7),  #  textfields can also be sortable
            TextField('type'),
            NumericField('length', sortable=True),  #  numericfields cannot have weights
            NumericField('rating', sortable=True),
        )
        #  index creation. 
        #  using IndexDefinition(prefix= will index automagically all redis keys that have this prefix
        client.ft(index_name).create_index(schema, definition=IndexDefinition(prefix=['flower:']))
    
        #  since the index is new we need to load the data (if it does not exist on redis already)
    
        flowers = [
            {'name': 'gladiola', 'type': 'cactus', 'length': 22, 'rating': 3.57, 'color': 'violet'},
            {'name': 'eleanor', 'type': 'cactus,pine', 'length': 15, 'rating': 4.34, 'color': 'brown'},
            {'name': 'loveme', 'type': 'berry', 'length': 13, 'rating': 5, 'color': 'blue'},
        ]
    
        for i, flower in enumerate(flowers):
            pipe = client.pipeline()
            pipe.hset(name='flower:' + str(i), key='name', value=flower['name'])
            pipe.hset(name='flower:' + str(i), key='type', value=flower['type'])
            pipe.hset(name='flower:' + str(i), key='length', value=flower['length'])
            pipe.hset(name='flower:' + str(i), key='rating', value=flower['rating'])
            pipe.hset(name='flower:' + str(i), key='color', value=flower['color'])
            pipe.execute()
    

    all these hashes will be indexed because their key has the prefix 'flower:'

    searching:

    #  first we need to get the index we are going to work with
    index = client.ft(index_name)
    
    #  wildcard search from both sides on all searchable fields
    results = index.search(Query('*actu*'))  
    results = results.docs
    for result in results:
        print(result.__dict__)
    
    #  sort by a sortable field in ascending order (you can sort by a non-sortable field but it will be slower)
    results = index.search(Query('*actu*').sort_by(field='length', asc=True))
    
    #  pagination. 'num' is size of the page
    results = index.search(Query('*actu*').paging(offset=0, num=10))
    
    #  search a specific field
    results = index.search(Query('@name:*actu*'))
    
    #  search specific fields - OR operation
    results = index.search(Query('@name|type:*actu*'))
    
    #  search specific fields - AND operation
    results = index.search(Query('@name:*actu* @type:*actu*'))
    
    #  sort by multiple fields - length and rating. We need to use Aggregation to achieve this
    request = AggregateRequest(
        query='@name|type:*actu*'
        ).sort_by(
            Asc('@length'), 
            Desc('@rating'), 
        ).limit(  #  pagination
            0, 10
        ).load(  #  we need to indicate the fields we want to get in results
            '@name', 
            '@type', 
            '@length', 
            '@rating', 
            '@color', 
        )
    #  perform aggregate search
    results = index.aggregate(request)
    print(results.rows)
    

    Point out mistakes and improvements, I'll gladly edit the answer.