PolarDB for MySQL offers native columnstore full-text search based on the In-Memory Column Index (IMCI). You can create full-text indexes directly on existing tables and achieve millisecond-level fuzzy queries through the MATCH function and the optimized LIKE acceleration capability. Compared with external search engine solutions such as Elasticsearch, IMCI provides transactional consistency between data and indexes, avoids data synchronization latency, and reduces the complexity of the overall architecture.
Key concepts
To understand full-text search in PolarDB IMCI, you must understand the following key concepts:
|
Concept |
Description |
|
Document |
A unit of raw data to be indexed. In PolarDB IMCI, a document specifically refers to a row of data in the column store. |
|
Term |
The basic linguistic unit extracted from a document after tokenizer processing. It is the smallest unit for indexing and querying. |
|
Tokenizer |
A component that splits raw text into a sequence of terms. PolarDB IMCI provides multiple tokenizers (such as |
|
Inverted index |
The core data structure of full-text search, which records the mapping between each term and the list of documents that contain it. It consists of a term dictionary and posting lists, and accelerates text queries. |
|
Term dictionary |
Stores the collection of all terms and provides fast lookup. PolarDB IMCI uses the FST (Finite State Transducer) algorithm to build the dictionary. The query time complexity is O(len(term)), with low space usage. |
|
Posting list |
Records the list of all document IDs (64-bit row numbers in IMCI) that contain a specific term. PolarDB IMCI uses the RBM (Roaring Bitmap) algorithm to compress and compute posting lists, which performs well in both sparse and dense data scenarios. |
The following table compares the built-in PolarDB IMCI solution with the external "database + Elasticsearch" solution:
|
Comparison dimension |
PolarDB IMCI full-text search |
"Database + Elasticsearch" solution |
|
Data consistency |
Strong consistency. Index updates and data writes complete within the same transaction and follow ACID principles, so there is no data latency or inconsistency risk. |
Eventual consistency. Data must be synchronized from the database to Elasticsearch, which introduces synchronization latency. Data timeliness and transactional atomicity cannot be guaranteed. |
|
Architecture complexity |
Simple. The feature is built into the database. No new components are required and the architecture stays clear. |
Complex. You must deploy and maintain a separate Elasticsearch cluster and a data synchronization pipeline, which increases the heterogeneity of the system. |
|
Query method |
Unified. All data, structured and unstructured, is queried with standard SQL. |
Fragmented. You must use both SQL and the Elasticsearch DSL for queries, which often leads to two-stage queries that first query Elasticsearch and then query the database, adding latency and code complexity. |
|
O&M cost |
Low. Reuses the O&M and high availability systems of PolarDB. No dedicated O&M skills or extra server resources are required. |
High. Requires dedicated server resources and professional Elasticsearch O&M capabilities. Storing two copies of the data also increases storage cost. |
How it works
Full-text search in PolarDB IMCI is based on inverted index technology. It converts unstructured text data into a structured index, which significantly improves keyword query performance. The core process is shown in the following figure:

When data is written, the content of the InnoDB table is synchronized to Pack files in PolarStore through the columnstore index. During the query phase, the executor builds the inverted index on the columnstore data and uses Fts files to complete full-text matching efficiently. This architecture lets the row store and the column store work together, which balances write performance and complex query capabilities.

PolarDB IMCI uses a unified hybrid storage architecture that supports multiple query modes. As shown in the figure, full-text search relies on the Hybrid Storage Engine to build and maintain inverted indexes for efficient text search. It also combines elastic compute nodes with tiered storage to balance high-throughput writes and low-latency queries. On this basis, the built-in vector index capability further supports combined multi-modal retrieval of text and vectors. This architecture applies to scenarios such as e-commerce product search, log analysis, and knowledge base retrieval, and provides users with a one-stop data service platform that integrates OLTP, real-time analytics, full-text search, and vector search.
Tokenizers
Tokenization is the process of splitting text into terms and is the foundation of full-text search. Choosing an appropriate tokenizer is critical to retrieval accuracy and performance. IMCI supports the following tokenizers:
|
Tokenizer |
Description |
|
token |
Splits text on non-alphanumeric characters such as spaces and punctuation. Suitable for English and other languages that use spaces as separators. |
|
ngram |
Splits text into continuous terms of a preset character length (n). |
|
jieba |
Built on the |
|
ik |
Built on |
|
json |
Extracts specific key values or array elements from a JSON object as terms by using JSONPath expressions. Used for in-depth retrieval of JSON data. |
In addition, PolarDB IMCI provides the dbms_imci.fts_tokenize tokenization utility function to test tokenization results. It supports all tokenizers and their corresponding properties. Different tokenization results may cause full-text index query results to differ from expectations or cause MATCH and LIKE to return inconsistent results. In this case, you can use this tokenization utility function to verify the tokenization results.
Posting lists
Intuitively, a posting list (Postings List) is a set of document IDs. Its key technical points lie in highly efficient compressed storage and high-performance computation (such as intersection).
In a PolarDB IMCI full-text index, a posting list stores the set of row numbers of all columnstore index rows that contain a specific term, together with the corresponding term frequency (optional) and document frequency (optional). Each term corresponds to one posting list.
IMCI uses the RBM (Roaring Bitmaps) algorithm to compress and compute posting lists (that is, sets of document IDs).

The RBM implementation is based on the CRoaring library and dynamically selects a storage strategy based on data density:
-
If the number of document IDs in the posting list is smaller than a preset threshold,
std::arrayis used for storage. -
If the number exceeds the threshold, the storage switches to the
roaring::Roaring64Maptype to handle large-scale sparse or dense data while maintaining a high compression ratio.
Performance characteristics:
-
Supports lookups with O(logN) complexity during index building.
-
Supports SIMD instruction acceleration for set operations such as intersection and union.
-
Supports space reorganization when data is written to disk to reduce fragmentation.
-
Supports using
minimum/maximumvalues for fast filtering and iterator optimization during queries.
Term dictionary
The core idea of an inverted index is to use a dictionary to quickly find the posting list that a term maps to. The design of the term-to-posting-list dictionary is therefore particularly important. Common designs include a trie, a B+ tree, and an FST.
IMCI uses the FST (Finite State Transducer) algorithm to build the term dictionary to balance time efficiency and space efficiency.
-
Space efficiency: By sharing the common prefixes and suffixes of terms, the storage space is effectively compressed.
-
Time efficiency: The time complexity of a term lookup is O(L), where L is the length of the term.
For example, assume that the terms China, Chinese, and love are inserted in order and that their posting list address offsets are 5, 10, and 15. The dictionary that is built is shown in the following figure. The figure shows that the FST not only shares common prefixes and suffixes to save space, but also guarantees that each transition has a unique associated value. A query starts from initial state 0 and checks each character of the term for an outgoing edge of that character. If the edge exists, the query accumulates the associated value. Otherwise, the query checks whether the current state is a final state. For example, Chinese accumulates an associated value of 15 and its last character is a final state, which means that the term exists in the dictionary. In addition, FST prefix calculation is byte-based rather than character-based, so it also supports encodings such as UTF-8. 
Inverted index building
PolarDB IMCI uses the SPIMI algorithm to build inverted indexes. Through a single scan, tokenization, and batch generation of the dictionary and posting lists, it supports efficient local index building with controlled memory usage.
When the PolarDB IMCI full-text index is built with SPIMI, IMCI continuously reads the columnstore data of the target column, tokenizes each row to obtain a set of terms, and then adds each term and its corresponding row number to a hash table while accumulating a memory usage value. When the memory usage exceeds the segment size threshold, IMCI builds a dictionary from the terms and posting lists in the hash table, resets the memory, and continues with the next row until all columnstore data is processed. The main process for building a dictionary (FST) from the hash table (std::unordered_map) is as follows: first sort the hash table by term (key); then serialize all posting lists in the hash table to disk in order and record their relative offset addresses on disk; then add each term and the posting list offset address of that term to the FST algorithm in order to build the dictionary; finally compress the dictionary, write it to disk, and record the current segment information (including the dictionary size, the dictionary start address, the posting list start address, and the row number range) in the metadata. PolarDB does not build a global dictionary in order to avoid external sorting (a global dictionary would also have to be split by prefix so that a term index could be built on it). Instead, because columnstore storage uses an append-only write model, PolarDB uses a lightweight build method that produces multiple local dictionaries based on the memory threshold, as shown in the following figure. When memory is sufficient, increase the memory threshold as much as possible. More instances of the same term then fall into the same inverted segment, which saves space and improves query performance. 
In addition to the normal inverted index building described above, the PolarDB IMCI full-text index also supports asynchronous merging of inverted indexes when the system is idle in the background. The PolarDB IMCI columnstore index is a secondary index of a regular table. On INSERT, data is always appended to the columnstore storage engine by column in insertion order. DELETE uses mark-for-deletion, and UPDATE is converted to DELETE plus INSERT. IMCI uses array InsertMask to mark the insert version of each row in the columnstore data for visibility checks, and uses lsm DeleteMask to mark an existing row as deleted. At the same time, background operations such as asynchronous Compaction and Recycle reorganize data and reclaim space. As part of the columnstore engine, the PolarDB IMCI full-text index also uses a background asynchronous inverted index Compaction task to periodically clean up data that is marked as deleted, which saves space and improves query performance. Inverted index merging uses the inverted segment as its unit: multiple inverted segments are merged into a new inverted segment, and the original inverted segments are not modified. This prevents the inverted index snapshot objects that queries use from becoming invalid. When the merge finishes, a new inverted index snapshot is generated, and new queries use the new snapshot. Thanks to the local build method and the mark-for-deletion design, a bulk insert does not trigger a global rebuild in the PolarDB IMCI full-text index and only the incremental part is built. The update cost is also very low because only a deletion mark is required, so write performance is not affected even in frequent update scenarios. In addition, periodic background asynchronous merging produces more compact inverted indexes to improve query performance. Combined with the concurrent query capability of the column store, this meets millisecond-level response requirements even in massive data scenarios.
Inverted index retrieval
The PolarDB IMCI full-text index supports the official MySQL MATCH function and the LIKE operator.
-
MATCHfunctionPolarDB IMCI supports using the
MATCHfunction for full-text search regardless of whether a full-text index exists in the row store. If no row store index exists, the query is routed directly to the column store node. If a row store index exists, the query is intelligently distributed based on cost evaluation. To keep the time-consuming operations that a native MySQL full-text index triggers during the optimization phase, such as auxiliary table synchronization and cache loading, from affecting column store performance, PolarDB skips these operations at the start of query distribution.During the execution phase, IMCI provides two retrieval methods: the
FtsTableScanoperator and theMATCHexpression. The former obtains matching rows directly from the inverted index and suits scenarios with a high filter ratio. The latter looks up the index by row number and suits scenarios in which preceding conditions have already filtered out most of the data. The execution efficiency of both methods depends on how well other predicates filter data. The column store optimizer therefore estimates the filter ratio from statistics and dynamically selects the optimal strategy. When the operator method is selected, the system automatically rewrites theMATCHfunction intoFtsTableScan + Filteroperators.The full-text index is built asynchronously, which can briefly delay the visibility of new data. By default, the column store executor completes the query results with a full table scan over unindexed data to ensure the completeness of query results. A parameter controls whether to skip that step, so you can flexibly balance performance and consistency in scenarios with high concurrency and large data volumes. You can also adjust index building parameters to increase the data synchronization frequency and narrow the scope of the full table scan, which further improves query efficiency.
-
LIKEaccelerationUnder specific conditions, PolarDB IMCI supports mutual conversion between
LIKEandMATCH. ConvertingLIKEtoMATCHis mainly used for query acceleration to reduce the overhead of row-by-row comparison of large amounts of strings in full table scans.Currently, this conversion takes effect only when the columnstore full-text index uses the
ngramtokenizer and thengramtoken length is less than or equal to the length of theLIKEpattern string. Under this condition, the optimizer can rewrite a predicate such asLIKE '%abc%'intoFtsTableScan + Filteroperators, using the inverted index to quickly filter candidate rows.However, because the matching mechanism of
ngramtokenization differs from the semantics ofLIKE(for example,"abbc"tokenizes toab,bb, andbc, which overlap with"abc"'sabandbcand may be falsely judged as a match), the originalLIKEexpression is retained as a subsequent filter condition for exact verification to ensure result correctness.This mechanism significantly improves query performance while effectively balancing semantic accuracy and execution efficiency.
The PolarDB IMCI inverted index consists of multiple inverted segments. Each inverted segment contains its own metadata, one term dictionary, and a series of posting lists, where each term uniquely corresponds to one posting list. The metadata records information such as the start addresses of the dictionary and the posting lists. The metadata is small and resides in memory by default to accelerate index access.
Inverted index retrieval is performed per inverted segment. The main process includes reading the dictionary data, building the FST (Finite State Transducer) dictionary object, looking up the target term in the dictionary, and reading the corresponding posting list to build the RBM (Roaring Bitmap) posting list object.
Specifically, queries are divided into two modes:
-
Operator query: Traverses the metadata of all inverted segments, obtains the dictionary start address, loads the dictionary data, builds the dictionary object, and looks up the target term. If the term is found, it combines the posting list offset address of the term with the start address in the segment to read the complete posting list object.
-
Expression query: Determines the set of inverted segments based on the row number, further filters by the row number range in the metadata, and then performs a dictionary lookup and posting list read similar to the operator query on the matching inverted segments.
To improve performance, IMCI supports term dictionary caching. It uses an independent LRU (Least Recently Used) caching mechanism, and the scheduling module dynamically adjusts the memory quota of that cache. A single posting list is usually small (most require only one 4 KB I/O), and posting lists are also numerous, so the cache hit ratio and the benefit of caching them are limited. Posting list caching is therefore disabled by default to avoid wasting memory resources.
This design balances memory usage and I/O overhead while ensuring query efficiency.
Use cases
The PolarDB IMCI full-text search feature applies to many business scenarios that require fast search over text content.
-
E-commerce product search and on-site queries
On an e-commerce platform, users often search for products by keyword. Traditional fuzzy matching based on
LIKEperforms poorly and cannot meet response requirements under high concurrency. An external Elasticsearch solution speeds up search, but its synchronization latency often makes search results include products that are delisted, repriced, or out of stock, which degrades the user experience.PolarDB IMCI provides native full-text search and builds efficient inverted indexes on text fields such as product titles, descriptions, and attributes. Queries complete keyword matching inside the database, which avoids cross-system latency and keeps search results strongly consistent with the real-time state of each product, such as its price and inventory. What a user finds is what the user can actually buy.
-
Log analysis and observability
During O&M and troubleshooting, developers and O&M engineers must quickly locate error stacks, trace request chains, or analyze abnormal behavior in massive volumes of logs. The traditional ELK architecture is powerful, but it has many components, is complex to deploy, and is expensive to maintain. It also introduces a noticeable delay between the time data is written and the time it becomes queryable.
With PolarDB IMCI, you can create a full-text index directly on the
messageorcontentfield of a log table and use standard SQL for millisecond-level log retrieval. You can run interactive queries and trace context without building a separate log analysis platform. This significantly simplifies the technology stack, reduces storage and O&M overhead, and makes issue location more efficient. -
Document and knowledge base retrieval
For an internal knowledge base, product manual, FAQ, or help center, the core requirement is to let users find the information they need quickly. Relying on an external search engine means that you must maintain dual-write logic, and content can easily fall out of sync after an update.
Build a full-text index on the document body with PolarDB IMCI and use a Chinese tokenizer such as
jiebaorikto improve tokenization accuracy. You can then store and retrieve content in the same database. Content is searchable immediately after it is updated, the permission model reuses your existing system, and no extra synchronization mechanism is required. Published content is visible immediately, and an edit takes effect immediately. -
User profiling and behavior analysis
Precise user operations depend on in-depth mining of unstructured text, such as extracting interests and preferences from user comments, tags, and posts. The traditional approach exports data to a data warehouse or an analytics system, which is a complex process with poor timeliness.
PolarDB IMCI supports building indexes with the
jsontokenizer on JSON fields or thejiebatokenizer on long text fields. A single SQL statement can then combine structured attributes, such as age and region, with text semantics, such as "enjoys outdoor sports" or "focuses on value for money", for joint analysis. User segmentation and behavior insights are completed in real time without data migration, which supports refined operations and personalized recommendation.
Performance benchmark
ESRally is the official Elasticsearch benchmarking tool from Elastic. This topic uses its built-in http_logs dataset to evaluate the retrieval performance of the PolarDB IMCI columnstore full-text index.
Prepare the dataset
-
Get the dataset:
For details about the dataset, see Elasticsearch Rally Hub. You can obtain the dataset as follows. The compressed package rally-track-data-http_logs.tar is about 1.7 GB. After decompression, the dataset is about 32 GB and contains 247 million rows in total.
git clone https://github.com/elastic/rally-tracks.git cd rally-tracks ./download.sh http_logs -
Create a table:
Because a small number of rows in the dataset contain JSON data that is incompatible with the MySQL JSON type, varchar(512) is used to store the JSON data. After the data is imported, a virtual column is used to parse the request field out of the JSON.
CREATE TABLE http_logs( logs varchar(4096) ); -
Import data:
Use LOAD DATA to import the dataset into the database.
LOAD DATA INFILE '/home/xxx/http_logs/documents-181998.json' INTO TABLE http_logs COLUMNS TERMINATED BY '\n'; ... ... -
Add a column:
Use a virtual column to parse the request field out of the JSON for full-text index testing.
ALTER TABLE http_logs ADD COLUMN request varchar(1024) AS (CASE WHEN json_valid(logs) THEN (json_unquote(json_extract(logs, '$.request'))) ELSE NULL END); -
Create a columnstore index:
The columnstore inverted index is part of the columnstore index, so you must create the columnstore index first.
ALTER TABLE http_logs comment 'columnar=1'; -
Create an inverted index:
The columnstore inverted index is created by modifying the column comment through DDL. The DDL statement completes in seconds, and the inverted index is built asynchronously in the background.
ALTER TABLE http_logs modify COLUMN request varchar(1024) AS (CASE WHEN json_valid(logs) THEN (json_unquote(json_extract(logs, '$.request'))) ELSE NULL END) comment 'imci_fts(type=2 mode=1)'; -
View the inverted index:
After the index is created, you can run the following statements to view NUM_PACKS and NEXT_PACK_ID respectively. NUM_PACKS indicates the number of columnstore data blocks, and NEXT_PACK_ID indicates the number of the data block up to which the inverted index has been built. When the two values are close, the inverted index is built.
SHOW imci indexes; SHOW imci indexes fulltext;
Performance benchmark
After the inverted index is built, you can use the MATCH function to test the retrieval performance of terms from high frequency to low frequency. The following figure shows the query performance comparison of LIKE, MATCH, and Doris MATCH_ANY on the same dataset.
Single-threaded test results with hot data are as follows:
|
Query |
High-frequency term |
Relatively high-frequency term |
Relatively low-frequency term |
Low-frequency term |
|
LIKE |
1 min 21.96 sec |
1 min 18.44 sec |
1 min 24.59 sec |
1 min 31.19 sec |
|
SIMD LIKE |
25.46 sec |
22.80 sec |
21.98 sec |
21.60 sec |
|
MATCH (proprietary FTS library) |
2.43 sec |
0.25 sec |
0.01 sec |
0.00 sec |
|
Doris MATCH_ANY (CLucene library) |
3.49 sec |
0.24 sec |
0.03 sec |
0.03 sec |
As shown in the preceding table, MATCH delivers a significant performance improvement over LIKE and is largely unaffected by whether the data is hot or cold.
FAQ
Q1: What are the advantages of PolarDB IMCI full-text search over the built-in full-text index of a traditional database such as MySQL InnoDB?
PolarDB IMCI has advantages in performance, features, and scalability:
-
Performance: Based on column storage and a vectorized execution engine, and combined with algorithms such as FST and RBM, the query performance is better than that of traditional row store indexes, enabling fast responses in scenarios with high concurrency and massive data volumes.
-
Features: Built-in Chinese tokenizers such as
jiebaandik, as well as thejsontokenizer, meet the requirements of complex business scenarios. -
Write performance impact: The optimized index building and update mechanisms have a much smaller performance impact on high-frequency write scenarios (INSERT/UPDATE) than the full-text indexes of traditional databases.
-
Horizontal scalability: Benefits from the decoupled storage and compute architecture of PolarDB, with good horizontal scalability.
Q2: How do I choose an appropriate tokenizer for my business data?
Choose a tokenizer based on your data type and query requirements:
-
For Chinese text: Use the
jiebaoriktokenizer. Both perform semantic tokenization, which improves the accuracy of Chinese retrieval. -
For English or symbol-delimited text: Use the
tokentokenizer. It splits text on spaces and punctuation. -
For fuzzy matching or arbitrary substring search: Use the
ngramtokenizer. It splits text into fixed-length phrases (such as bigrams and trigrams), which makes it a good replacement for inefficientLIKE '%keyword%'queries. -
For specific content in JSON fields: Use the
jsontokenizer. It currently supports building inverted indexes on the values of a JSON array or the keys of a JSON object.
If you are not sure which tokenizer fits best, use the dbms_imci.fts_tokenize function to preview how different tokenizers process sample text, and then choose the tokenization strategy that best matches your business expectations.