All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Accelerate queries with multi-column indexes by using TairSearch

Last Updated:Mar 28, 2026

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 typeStandard Redis behaviorWorkaround required
Primary key queriesHMGET returns specific hash fields directlyNone
Secondary index queriesCannot query by hash fieldTwo-layer hash structure—adds import complexity and wastes memory due to data redundancy
Multi-column index queriesCannot filter across multiple hash fields simultaneouslyLua 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:

FieldTypeNotes
departurekeywordDeparture city, exact-match string
destinationkeywordArrival city, exact-match string
datekeywordDate stored as exact-match string
seatkeywordSeat class (for example, first)
withkeywordPassenger type (for example, baby)
flight_idkeywordFlight number
pricedoubleTicket price
departure_timelongDeparture time as Unix timestamp
destination_timelongArrival time as Unix timestamp
Important

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:

OK
Note

To 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:

OccurrenceBehavior
mustThe clause must match. Acts as logical AND, contributing to the relevance score.
shouldThe clause should match. Acts as logical OR.
filterThe clause must match, but does not affect the relevance score.
must_notThe 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:

  1. hits.hits: The array of matching documents.

  2. _id: The unique document identifier assigned by TairSearch.

  3. _index: The index the document belongs to.

  4. _score: The relevance score for this document.

  5. _source: The original document fields.

  6. hits.max_score: The highest relevance score among all matching documents.

  7. hits.total.value: The total number of matching documents (1 in this example).

  8. hits.total.relation: eq means the count is exact, not approximate.

What's next

For the full TairSearch command reference and advanced query options, see TairSearch.