All Products
Search
Document Center

PolarDB:An analysis of the full-text search feature in IMCI

Last Updated:Aug 27, 2026

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 jieba, ik, ngram, and json) to fit different languages and business scenarios.

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:

image

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.

image

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 jieba Chinese tokenization library. Supports precise mode, full mode, and search engine mode, and tokenizes text intelligently based on semantics.

ik

Built on IK Analyzer, another widely used Chinese tokenization tool that is common in search engines such as Elasticsearch.

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).

image.png

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::array is used for storage.

  • If the number exceeds the threshold, the storage switches to the roaring::Roaring64Map type 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/maximum values 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. image.png

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. image.png

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.

  • MATCH function

    PolarDB IMCI supports using the MATCH function 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 FtsTableScan operator and the MATCH expression. 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 the MATCH function into FtsTableScan + Filter operators.

    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.

  • LIKE acceleration

    Under specific conditions, PolarDB IMCI supports mutual conversion between LIKE and MATCH. Converting LIKE to MATCH is 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 ngram tokenizer and the ngram token length is less than or equal to the length of the LIKE pattern string. Under this condition, the optimizer can rewrite a predicate such as LIKE '%abc%' into FtsTableScan + Filter operators, using the inverted index to quickly filter candidate rows.

    However, because the matching mechanism of ngram tokenization differs from the semantics of LIKE (for example, "abbc" tokenizes to ab, bb, and bc, which overlap with "abc"'s ab and bc and may be falsely judged as a match), the original LIKE expression 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:

  1. 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.

  2. 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 LIKE performs 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 message or content field 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 jieba or ik to 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 json tokenizer on JSON fields or the jieba tokenizer 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

  1. 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
  2. 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)
    );
  3. 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';
    ... ...
  4. 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);
  5. 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';
  6. 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)';
  7. 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.

High-frequency term, almost all rows hit, about 247 million

SELECT COUNT(*) FROM http_logs WHERE request LIKE "%HTTP%";
SELECT COUNT(*) FROM http_logs WHERE MATCH(request) against("HTTP");
SELECT COUNT(*) FROM http_logs WHERE request MATCH_ANY 'HTTP';

Relatively high-frequency term, about 15 million rows hit

SELECT COUNT(*) FROM http_logs WHERE request LIKE "%french%";
SELECT COUNT(*) FROM http_logs WHERE MATCH(request) against("french");
SELECT COUNT(*) FROM http_logs WHERE request MATCH_ANY 'french';

Relatively low-frequency term, about 80,000 rows hit

SELECT COUNT(*) FROM http_logs WHERE request LIKE "%POST%";
SELECT COUNT(*) FROM http_logs WHERE MATCH(request) against("POST");
SELECT COUNT(*) FROM http_logs WHERE request MATCH_ANY 'POST';

Low-frequency term, about 100 rows hit

SELECT COUNT(*) FROM http_logs WHERE request LIKE "%Mozilla%";
SELECT COUNT(*) FROM http_logs WHERE MATCH(request) against("Mozilla");
SELECT COUNT(*) FROM http_logs WHERE request MATCH_ANY 'Mozilla';

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 jieba and ik, as well as the json tokenizer, 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 jieba or ik tokenizer. Both perform semantic tokenization, which improves the accuracy of Chinese retrieval.

  • For English or symbol-delimited text: Use the token tokenizer. It splits text on spaces and punctuation.

  • For fuzzy matching or arbitrary substring search: Use the ngram tokenizer. It splits text into fixed-length phrases (such as bigrams and trigrams), which makes it a good replacement for inefficient LIKE '%keyword%' queries.

  • For specific content in JSON fields: Use the json tokenizer. 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.