Standard Redis key-value storage cannot filter across multiple hash fields simultaneously—multi-column index queries require Lua scripting or on-disk computing. TairSearch adds inverted index support directly in Redis memory, letting you run multi-column index queries and LIKE-based fuzzy match queries without an additional processing layer.
How TairSearch handles multi-column queries
When you import data from a relational database into Redis, rows are stored as hashes: the primary key becomes the hash key, and other fields become hash fields and values.
| Query type | Standard Redis behavior | Workaround required |
|---|---|---|
| Primary key queries | HMGET returns specific hash fields directly | None |
| Secondary index queries | Cannot query by hash field | Two-layer hash structure—adds import complexity and wastes memory due to data redundancy |
| Multi-column index queries | Cannot filter across multiple hash fields simultaneously | Lua scripting or on-disk computing |
TairSearch fills this gap by storing data as documents with an Elasticsearch-compatible JSON mapping format. You create an index, write documents, and query them using a boolean DSL—no additional processing layer required.
Example: flight ticket search during traffic surges
This example shows how to use TairSearch to store and query flight information. During public holidays, traffic surges can occur as a result of large volumes of searches for flights to popular tourist destinations.
The example walks through three steps: create an index, write a document, and search for flights.
Step 1: Create a document index
The index key for this route is zhuhai_hangzhou—a combination of the departure place and destination.
Before creating the index, review the field types used in this schema:
| Field | Type | Notes |
|---|---|---|
departure | keyword | Departure city, exact-match string |
destination | keyword | Arrival city, exact-match string |
date | keyword | Date stored as exact-match string |
seat | keyword | Seat class (for example, first) |
with | keyword | Passenger type (for example, baby) |
flight_id | keyword | Flight number |
price | double | Ticket price |
departure_time | long | Departure time as Unix timestamp |
destination_time | long | Arrival time as Unix timestamp |
Use keyword for fields you want to filter by exact match—such as dates, IDs, and categories. keyword fields are more space-efficient and result in faster exact-match queries than text fields. Use text only when you need full-text search with tokenization.
Run TFT.CREATEINDEX to create the index:
TFT.CREATEINDEX zhuhai_hangzhou '{
"mappings":{
"properties":{
"departure":{"type":"keyword"},
"destination":{"type":"keyword"},
"date":{"type":"keyword"},
"seat":{"type":"keyword"},
"with":{"type":"keyword"},
"flight_id":{"type":"keyword"},
"price":{"type":"double"},
"departure_time":{"type":"long"},
"destination_time":{"type":"long"}
}
}
}'Expected output:
OKTo add or modify fields after index creation, use TFT.UPDATEINDEX.
Step 2: Write data to a document
Run TFT.ADDDOC to add a flight record to the zhuhai_hangzhou index:
TFT.ADDDOC zhuhai_hangzhou '{
"departure":"zhuhai",
"destination":"hangzhou",
"date":"2022-09-01",
"seat":"first",
"with":"baby",
"flight_id":"CZ1000",
"price":986.1,
"departure_time":1661991010,
"destination_time":1661998210
}'Expected output (the document ID returned in JSON format):
"{"_id":"16615908912020060"}"Step 3: Search for flight information
TFT.Search uses a boolean query DSL similar to Elasticsearch's Query DSL. The following table describes the four occurrence types available in a bool query:
| Occurrence | Behavior |
|---|---|
must | The clause must match. Acts as logical AND, contributing to the relevance score. |
should | The clause should match. Acts as logical OR. |
filter | The clause must match, but does not affect the relevance score. |
must_not | The clause must not match. |
The following query retrieves first-class flights from Zhuhai to Hangzhou on September 1, 2022, sorted by departure time:
TFT.Search zhuhai_hangzhou '{"sort":["departure_time"],"query":{"bool":{"must":[{"term":{"date":"2022-09-01"}},{"term":{"seat":"first"}}]}}}'This query uses bool.must with two term clauses—equivalent to the following SQL:
SELECT * FROM zhuhai_hangzhou
WHERE date = '2022-09-01' AND seat = 'first'
ORDER BY departure_time;Expected output:
{
"hits": {
"hits": [
{
"_id": "16615908912020060",
"_index": "zhuhai_hangzhou",
"_score": 0.433955,
"_source": {
"departure": "zhuhai",
"destination": "hangzhou",
"date": "2022-09-01",
"seat": "first",
"with": "baby",
"flight_id": "CZ1000",
"price": 986.1,
"departure_time": 1661991010,
"destination_time": 1661998210
}
}
],
"max_score": 0.433955,
"total": {
"relation": "eq",
"value": 1
}
}
}Key response fields:
hits.hits: The array of matching documents._id: The unique document identifier assigned by TairSearch._index: The index the document belongs to._score: The relevance score for this document._source: The original document fields.hits.max_score: The highest relevance score among all matching documents.hits.total.value: The total number of matching documents (1in this example).hits.total.relation:eqmeans the count is exact, not approximate.
What's next
For the full TairSearch command reference and advanced query options, see TairSearch.