Search JSON quick start
This quick start shows you how to index JSON documents and run search queries against the index.
Prerequisites
For this quick start tutorial, you need:
-
Either:
-
A Redis Cloud database with Redis Stack
-
A Redis Enterprise Software database with RediSearch (v2.2 or later) and RedisJSON (v2.0 or later)
-
-
And:
Search JSON with redis-cli
To begin, connect to your database with redis-cli
.
Create an index
To create an index for JSON documents with FT.CREATE
, use the ON JSON
You also need to include a schema definition that indicates which JSON elements to index. When you define the schema, use a JSON path expression to map a specific JSON element to a schema field:
SCHEMA <JSONPath> AS <field_name> <TYPE>
The examples in this tutorial use the extended JSONPath syntax.
The schema for this example includes four fields:
name
(TEXT
)description
(TEXT
)connectionType
(TEXT
)price
(NUMERIC
)
This example defines the schema and creates the index:
127.0.0.1:12543> FT.CREATE itemIdx ON JSON PREFIX 1 item: SCHEMA $.name AS name TEXT $.description as description TEXT $.connection.type AS connectionType TEXT $.price AS price NUMERIC
After you create the index, RediSearch automatically adds all existing and future JSON documents prefixed with item:
to the index.
See Index limitations for more details about schema restrictions for JSON document indexes.
Add JSON documents
You can create and store JSON documents in the database with the JSON.SET
command.
The following examples use these JSON documents to represent individual inventory items.
Item 1 JSON document:
{
"name": "Noise-cancelling Bluetooth headphones",
"description": "Wireless Bluetooth headphones with noise-cancelling technology",
"connection": {
"wireless": true,
"type": "Bluetooth"
},
"price": 99.98,
"stock": 25,
"colors": [
"black",
"silver"
]
}
Item 2 JSON document:
{
"name": "Wireless earbuds",
"description": "Wireless Bluetooth in-ear headphones",
"connection": {
"wireless": true,
"type": "Bluetooth"
},
"price": 64.99,
"stock": 17,
"colors": [
"black",
"white"
]
}
To store these JSON documents in the database, run the following commands:
127.0.0.1:12543> JSON.SET item:1 $ '{"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","connection":{"wireless":true,"type":"Bluetooth"},"price":99.98,"stock":25,"colors":["black","silver"]}'
"OK"
127.0.0.1:12543> JSON.SET item:2 $ '{"name":"Wireless earbuds","description":"Wireless Bluetooth in-ear headphones","connection":{"wireless":true,"type":"Bluetooth"},"price":64.99,"stock":17,"colors":["black","white"]}'
"OK"
Search the index
To search the index for JSON documents that match a specified condition, use the FT.SEARCH
command. You can search any field defined in the index schema.
For more information about search queries, see Search query syntax.
Return the entire document
Search query results include entire JSON documents by default.
For example, search for Bluetooth headphones with a price less than 70:
127.0.0.1:6379> FT.SEARCH itemIdx '@description:(headphones) @connectionType:(bluetooth) @price:[0 70]'
1) "1"
2) "item:2"
3) 1) "$"
2) "{\"name\":\"Wireless earbuds\",\"description\":\"Wireless Bluetooth in-ear headphones\",\"connection\":{\"wireless\":true,\"connection\":\"Bluetooth\"},\"price\":64.99,\"stock\":17,\"colors\":[\"black\",\"white\"]}"
Return specific fields
If you want to limit the search results to include only specific parts of a JSON document, use field projection. The RETURN
option lets you specify which fields to include.
The following query uses the JSONPath expression $.stock
to return each item’s stock in addition to the name and price:
127.0.0.1:6379> FT.SEARCH itemIdx '@description:(headphones)' RETURN 5 name price $.stock AS stock
1) "2"
2) "item:1"
3) 1) "name"
2) "Noise-cancelling Bluetooth headphones"
3) "price"
4) "99.98"
5) "stock"
6) "25"
4) "item:2"
5) 1) "name"
2) "Wireless earbuds"
3) "price"
4) "64.99"
5) "stock"
6) "17"
Aggregate search results
The FT.AGGREGATE
command lets you run a search query and modify the results with operations such as SORTBY
, REDUCE
, LIMIT
, FILTER
, and more. For a detailed list of available operations and examples, see Aggregations.
To run aggregations on JSON documents, pass JSON path expressions to the LOAD
option. You can use any JSON element, even elements that are not included in the index schema.
This example uses aggregation operations to calculate a 10% price discount for each item and then sorts the items from least expensive to most expensive:
127.0.0.1:6379> FT.AGGREGATE itemIdx '*' LOAD 4 name $.price AS originalPrice APPLY '@originalPrice - (@originalPrice * 0.10)' AS salePrice SORTBY 2 @salePrice ASC
1) "2"
2) 1) "name"
2) "Wireless earbuds"
3) "originalPrice"
4) "64.99"
5) "salePrice"
6) "58.491"
3) 1) "name"
2) "Noise-cancelling Bluetooth headphones"
3) "originalPrice"
4) "99.98"
5) "salePrice"
6) "89.982"
Drop the index
To remove the index without deleting any associated documents, run the FT.DROPINDEX
command:
127.0.0.1:12543> FT.DROPINDEX itemIdx
OK
Search JSON with Python
If you want to use RediSearch within an application, these client libraries are available.
The following example uses the Redis Python client library redis-py
, which supports RediSearch commands as of v4.0.0.
This Python code indexes JSON documents, runs search and aggregation queries, and then deletes the index:
import redis
from redis.commands.search.field import TextField, NumericField
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from redis.commands.search.aggregation import AggregateRequest, Asc
# Connect to a database
r = redis.Redis(host="<endpoint>", port="<port>",
password="<password>")
# Options for index creation
index_def = IndexDefinition(
index_type=IndexType.JSON,
prefix = ['item:'],
score = 0.5,
score_field = 'doc_score'
)
# Schema definition
schema = ( TextField('$.name', as_name='name'),
TextField('$.description', as_name='description'),
TextField('$.connection.type', as_name='connectionType'),
NumericField('$.price', as_name='price')
)
# Create an index and pass in the schema
r.ft('py_item_idx').create_index(schema, definition = index_def)
# Dictionaries that represent JSON documents
doc1 = {
"name": "Noise-cancelling Bluetooth headphones",
"description": "Wireless Bluetooth headphones with noise-cancelling technology",
"connection": {
"wireless": True,
"type": "Bluetooth"
},
"price": 99.98,
"stock": 25,
"colors": [
"black",
"silver"
]
}
doc2 = {
"name": "Wireless earbuds",
"description": "Wireless Bluetooth in-ear headphones",
"connection": {
"wireless": True,
"type": "Bluetooth"
},
"price": 64.99,
"stock": 17,
"colors": [
"black",
"white"
]
}
# Add documents to the database and index them
r.json().set('item:1', '$', doc1)
r.json().set('item:2', '$', doc2)
# Search the index for a string
search_result = r.ft('py_item_idx').search(Query('@name:(earbuds)')
.return_field('name')
.return_field('price')
.return_field('$.stock', as_field='stock'))
# The result has the total number of search results and a list of documents
print('Results for "earbuds":')
print(search_result.total)
for doc in search_result.docs:
print(doc)
print()
# Use aggregation to calculate a 10% price discount for each item and sort them from least expensive to most expensive
aggregate_query = AggregateRequest('*').load('name', 'price').apply(salePrice='@price - (@price * 0.10)').sort_by(Asc('@salePrice'))
aggregate_result = r.ft('py_item_idx').aggregate(aggregate_query).rows
# Display the aggregation result
print('Aggregation result:')
for result in aggregate_result:
print(result)
# Delete the index; set delete_documents to True to delete indexed documents as well
r.ft('py_item_idx').dropindex(delete_documents=False)
Example output:
$ python3 quick_start.py
Results for "earbuds":
1
Document {'id': 'item:2', 'payload': None, 'name': 'Wireless earbuds', 'price': '64.99', 'stock': '17'}
Aggregation result:
[b'name', b'Wireless earbuds', b'price', b'64.99', b'salePrice', b'58.491']
[b'name', b'Noise-cancelling Bluetooth headphones', b'price', b'99.98', b'salePrice', b'89.982']