2023-01-26 13:58:10 +00:00
---
slug: /en/engines/table-engines/mergetree-family/invertedindexes
2023-01-26 14:05:28 +00:00
sidebar_label: Inverted Indexes
2023-01-26 15:06:06 +00:00
description: Quickly find search terms in text.
keywords: [full-text search, text search]
2023-01-26 13:58:10 +00:00
---
# Inverted indexes [experimental]
2023-01-19 18:38:07 +00:00
2023-01-26 15:51:08 +00:00
Inverted indexes are an experimental type of [secondary indexes ](/docs/en/engines/table-engines/mergetree-family/mergetree.md/#available-types-of-indices ) which provide fast text search
2023-01-26 15:06:06 +00:00
capabilities for [String ](/docs/en/sql-reference/data-types/string.md ) or [FixedString ](/docs/en/sql-reference/data-types/fixedstring.md )
2023-01-26 13:58:10 +00:00
columns. The main idea of an inverted index is to store a mapping from "terms" to the rows which contain these terms. "Terms" are
tokenized cells of the string column. For example, the string cell "I will be a little late" is by default tokenized into six terms "I", "will",
"be", "a", "little" and "late". Another kind of tokenizer is n-grams. For example, the result of 3-gram tokenization will be 21 terms "I w",
2023-01-19 18:38:07 +00:00
" wi", "wil", "ill", "ll ", "l b", " be" etc. The more fine-granular the input strings are tokenized, the bigger but also the more
useful the resulting inverted index will be.
:::warning
2023-01-26 13:58:10 +00:00
Inverted indexes are experimental and should not be used in production environments yet. They may change in the future in backward-incompatible
2023-01-19 18:38:07 +00:00
ways, for example with respect to their DDL/DQL syntax or performance/compression characteristics.
:::
## Usage
To use inverted indexes, first enable them in the configuration:
```sql
SET allow_experimental_inverted_index = true;
```
An inverted index can be defined on a string column using the following syntax
``` sql
2023-01-26 19:05:26 +00:00
CREATE TABLE tab
(
`key` UInt64,
`str` String,
2023-01-26 19:07:13 +00:00
INDEX inv_idx(str) TYPE inverted(0) GRANULARITY 1
2023-01-26 19:05:26 +00:00
)
ENGINE = MergeTree
ORDER BY key
2023-01-19 18:38:07 +00:00
```
where `N` specifies the tokenizer:
- `inverted(0)` (or shorter: `inverted()` ) set the tokenizer to "tokens", i.e. split strings along spaces,
- `inverted(N)` with `N` between 2 and 8 sets the tokenizer to "ngrams(N)"
2023-01-26 13:58:10 +00:00
Being a type of skipping index, inverted indexes can be dropped or added to a column after table creation:
2023-01-19 18:38:07 +00:00
``` sql
2023-01-29 23:12:32 +00:00
ALTER TABLE tab DROP INDEX inv_idx;
ALTER TABLE tab ADD INDEX inv_idx(s) TYPE inverted(2) GRANULARITY 1;
2023-01-19 18:38:07 +00:00
```
To use the index, no special functions or syntax are required. Typical string search predicates automatically leverage the index. As
examples, consider:
```sql
2023-01-29 23:12:32 +00:00
INSERT INTO tab(key, str) values (1, 'Hello World');
SELECT * from tab WHERE str == 'Hello World';
SELECT * from tab WHERE str IN ('Hello', 'World');
SELECT * from tab WHERE str LIKE '%Hello%';
SELECT * from tab WHERE multiSearchAny(str, ['Hello', 'World']);
SELECT * from tab WHERE hasToken(str, 'Hello');
2023-01-19 18:38:07 +00:00
```
The inverted index also works on columns of type `Array(String)` , `Array(FixedString)` , `Map(String)` and `Map(String)` .
Like for other secondary indices, each column part has its own inverted index. Furthermore, each inverted index is internally divided into
2023-01-26 13:58:10 +00:00
"segments". The existence and size of the segments are generally transparent to users but the segment size determines the memory consumption
2023-01-19 18:38:07 +00:00
during index construction (e.g. when two parts are merged). Configuration parameter "max_digestion_size_per_segment" (default: 256 MB)
controls the amount of data read consumed from the underlying column before a new segment is created. Incrementing the parameter raises the
2023-01-26 13:58:10 +00:00
intermediate memory consumption for index construction but also improves lookup performance since fewer segments need to be checked on
2023-01-19 18:38:07 +00:00
average to evaluate a query.
Unlike other secondary indices, inverted indexes (for now) map to row numbers (row ids) instead of granule ids. The reason for this design
is performance. In practice, users often search for multiple terms at once. For example, filter predicate `WHERE s LIKE '%little%' OR s LIKE
2023-01-26 13:58:10 +00:00
'%big%'` can be evaluated directly using an inverted index by forming the union of the row id lists for terms "little" and "big". This also
means that the parameter `GRANULARITY` supplied to index creation has no meaning (it may be removed from the syntax in the future).