This document describes how to build and use full-text indexes on the In-Memory Column Index (IMCI) of PolarDB for MySQL. By configuring inverted indexes through column-level COMMENT, you can leverage MATCH...AGAINST syntax or automatically optimized LIKE queries to achieve millisecond-level fuzzy search. This feature is based on IMCI's inverted index and term matching mechanism. For detailed principles, see An analysis of the full-text search feature in IMCI.
Version requirements
Your cluster version must meet the following requirements:
MySQL 8.0.1, and the minor version must be 8.0.1.1.52 or later.
MySQL 8.0.2, and the minor version must be 8.0.2.2.32 or later.
Syntax
PolarDB IMCI allows you to create, modify, or delete inverted indexes by specifying the column comment when creating a table or modifying the column comment through DDL.
Syntax
Define a full-text index when creating a table:
CREATE TABLE table_name ( column_name Data_Type COMMENT "imci_fts(type=VALUE [,KEY=VALUE])" ) COMMENT 'columnar=1';Use
ALTERto modify a column to add or modify an index:ALTER TABLE table_name MODIFY column_name Data_Type COMMENT "imci_fts(type=VALUE [,KEY=VALUE])";ImportantModifying
COMMENTmay trigger a rebuild of the inverted index. For large tables, we recommend that you perform this operation during off-peak hours.Use
ALTERto modify a column to delete an index:ALTER TABLE table_name MODIFY column_name Data_Type COMMENT 'imci_fts(enable=0)';
Parameters
You must set COMMENT to 'columnar=1' at the table level to create an IMCI column store table. Full-text indexes are configured through the column's COMMENT in the format imci_fts(TYPE=VALUE[, KEY=VALUE]...), where TYPE is required and KEY is optional. Multiple KEY pairs are separated by commas.
Tokenizer type (the
typeparameter):Tokenizer
typevalueDescription
token
0 (default)
Splits text by non-alphanumeric characters such as spaces and punctuation. Suitable for English or formatted text.
ngram
1
Splits text into fixed-length character chunks (controlled by the
lenparameter). Suitable for fuzzy matching across any language.jieba
2
A dictionary-based Chinese tokenizer. Suitable for semantic Chinese search.
ik
3
Another widely used Chinese tokenizer.
json
4
Extracts content from JSON fields using JSONPath expressions (requires the
exprparameter) to build indexes.whole
5
Does not split text. The entire column is treated as a single term. Primarily used for accelerating equality queries (such as = or IN).
mysql ngram
6
MySQL-compatible ngram tokenizer.
Configuration parameters (
KEY-VALUE):Parameter (KEY)
Default
Description
Applicable tokenizer types (
type)enable
1
1: Create an inverted index (default)0: Delete the inverted index
All
type
0
Specifies the tokenizer type (see the table above)
All
len
-
The token length for the
ngramtokenizer. Valid range:[1, 256)type=1(ngram),type=6(mysql ngram)mode
0
Tokenizer mode:
jieba (
type=2):0: Accurate mode (default)1: Full mode2: Search engine mode
ik (
type=3):0: Smart mode (default)1: Most fine-grained mode
json (
type=4):0: Legacy array mode (default)1: Array mode2: Key-value mode, such as"*.id","[*].id", etc.
type=2, 3, 4score
0
Whether to support sorting:
0: Disable term frequency (TF) and document frequency (DF) generation, ignore sorting (default)1: Enable relevance score sorting forMATCH ... AGAINST
All
seg_size
0
Specifies the inverted index segment size:
0: Use the value of theimci_fts_build_segment_sizesystem variableOther values: Specify an exact segment size
All
pack_cnt_min
0
Minimum number of data units for inverted index builds:
0: Use the value of theimci_fts_build_packcnt_minsystem variableOther values: Specify an exact value
All
pack_cnt_max
0
Maximum number of data units for inverted index builds:
0: Use the value of theimci_fts_build_packcnt_maxsystem variableOther values: Specify an exact value
All
stop_word
0
Whether to support stop words:
0: Not supported (default)1: Supported
All
case_sensitive
0
Whether the matching is case-sensitive:
0: Case-insensitive (default)1: Case-sensitive2: Determined by the column'scollatesetting (MySQL-compatible mode)3: Fully determined by the column'scollatesetting (entirely controlled bycollate)
All
phrase
0
Whether to record positional information for phrase queries:
0: Do not record positional information (default)1: Record positional information
All
synonym
0
Whether to support synonyms:
0: Not supported (default)1: Supported, query mode2: Supported, index mode (requires rebuilding the inverted index)
All
Examples
1: Create a full-text index
Create a full-text index on the column that requires text search, and choose a tokenizer based on your business needs.
Create a test table: Create a table with a column store index.
CREATE TABLE t1 ( id INT PRIMARY KEY, title VARCHAR(32) COMMENT "imci_fts(type=2)" )CHARSET utf8mb4 COMMENT 'columnar=1';(Optional) Modify the full-text index: Use the
ALTER TABLEstatement to add a full-text index to thetitlecolumn and specify the search engine mode of thejiebatokenizer.ALTER TABLE t1 MODIFY title VARCHAR(32) COMMENT "imci_fts(type=2,mode=0)";(Optional) Verify tokenization results: Before choosing a tokenizer, you can use the
dbms_imci.fts_tokenizefunction to preview how different tokenizers process text.CALL dbms_imci.fts_tokenize("I am PolarDB"); -- Result: ["i", "am", "polardb"] CALL dbms_imci.fts_tokenize("I am PolarDB", "type=1"); -- Result: ["i ", " a", "am", "m ", " p", "po", "ol", "ar", "rd", "db"] CALL dbms_imci.fts_tokenize("I am PolarDB", "type=2"); -- Result: ["PolarDB"] CALL dbms_imci.fts_tokenize("I am PolarDB", "type=2,mode=1"); -- Result: ["polardb"]
2: Run full-text search queries
After the index is created, IMCI builds it in the background. Once the build is complete, you can run text queries using MATCH...AGAINST or optimized LIKE statements.
Use
MATCH...AGAINSTqueries:-- Insert sample data INSERT INTO t1 VALUES (16, 'polarDB full-text index feature title'), (17, 'database title performance optimization'); -- Find rows where the title column contains "title" SELECT * FROM t1 WHERE MATCH(title) AGAINST("title");Use
EXPLAINto view the execution plan. If theFtsTableScanoperator appears, the query has hit the full-text index.EXPLAIN SELECT * FROM t1 WHERE MATCH(title) AGAINST("title") AND id > 10; +----+------------------------+------+-----------------------------------------------------------------+ | ID | Operator | Name | Extra Info | +----+------------------------+------+-----------------------------------------------------------------+ | 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = 41230008320) | | 2 | └─Compute Scalar | | | | 3 | └─FILTER | | Cond:(t1.id > 10) | | 4 | └─FtsTableScan | t1 | Term:("title") Fallback:(t1.title LIKE "%title%") | +----+------------------------+------+-----------------------------------------------------------------+Fallbackindicates that for incremental data not yet indexed, the system automatically usesLIKEsupplementary scans to ensure result completeness.Accelerate
LIKEqueries: To be compatible with existing application code, IMCI supports automatically converting specificLIKEqueries toMATCH...AGAINSTfor acceleration.SET imci_convert_like_to_match = on; EXPLAIN SELECT * FROM t1 WHERE title LIKE "%title%"; +----+------------------------+------+-----------------------------------------------------------------+ | ID | Operator | Name | Extra Info | +----+------------------------+------+-----------------------------------------------------------------+ | 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = 41230008320) | | 2 | └─Compute Scalar | | | | 3 | └─FILTER | | Cond:(t1.title LIKE "%title%") | | 4 | └─FtsTableScan | t1 | Term:("title") Fallback:(t1.title LIKE "%title%") | +----+------------------------+------+-----------------------------------------------------------------+The execution plan also displays the
FtsTableScanoperator, confirming that theLIKEquery has been successfully accelerated.MATCHtoLIKEconversion: When no full-text index exists, to ensure the query still runs correctly while leveraging existing indexes as much as possible, IMCI may convertMATCHtoLIKE, and the execution plan shows a full table scan.SET imci_enable_query_fts_like = on; EXPLAIN SELECT * FROM t1 WHERE MATCH(title) AGAINST("title"); +----+----------------------+------+-----------------------------------------------------------------+ | ID | Operator | Name | Extra Info | +----+----------------------+------+-----------------------------------------------------------------+ | 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = 41230008320) | | 2 | └─Compute Scalar | | | | 3 | └─Table Scan | t1 | Cond:(title LIKE "%title%") | +----+----------------------+------+-----------------------------------------------------------------+
3: Manage and monitor indexes
Query the build status and metadata of indexes, and delete indexes when they are no longer needed.
Monitor index build progress and status:
-- View all inverted indexes SHOW imci indexes fulltext; SELECT * FROM information_schema.imci_fts_indexes; -- View a specific inverted index SHOW imci indexes fulltext FOR [db_name].[table_name]; SELECT * FROM information_schema.imci_fts_indexes WHERE schema_name='[db_name]' AND table_name='[table_name]'; -- View metadata of a specific inverted index SELECT * FROM information_schema.imci_fts_index_metas WHERE schema_name='[db_name]' AND table_name='[table_name]' AND column_name='[column_name]'; -- View segment data of a specific inverted index SELECT * FROM information_schema.imci_fts_index_segs WHERE schema_name='[db_name]' AND table_name='[table_name]' AND column_name='[column_name]'; -- View column store data of a specific inverted index SELECT * FROM information_schema.imci_fts_index_packs WHERE schema_name='[db_name]' AND table_name='[table_name]' AND column_name='[column_name]';Delete a full-text index: If you no longer need a full-text index on a column, you can delete it by modifying the column's
COMMENT.ALTER TABLE t1 MODIFY title VARCHAR(255) COMMENT 'imci_fts(enable=0)';
4: Core system variables
Parameter | Scope | Description |
imci_enable_fts | Global | Whether to allow creating inverted indexes on column store nodes.
|
imci_enable_fts_query | Global / Session | Whether to allow using inverted indexes on column store nodes.
|
imci_fts_build_pack_cnt_min | Global | Minimum number of column store data blocks per inverted index during index builds. Valid range: 0-8192. Default value: 8. A value of 0 means the build is temporarily paused. |
imci_fts_build_pack_cnt_max | Global | Maximum number of column store data blocks per inverted index during index builds. Valid range: 0-8192. Default value: 128. |
imci_fts_build_segment_size | Global | Segment size for each inverted index during index builds. Valid range: 0-4294967295. Default value: 536870912 (512 MB), in bytes. |
imci_fts_lru_cache_capacity | Global | Cache space for inverted index dictionaries. Valid range: [DBNodeClassMemory*1/10~DBNodeClassMemory*1/2]. Default value: [DBNodeClassMemory*10/100]. |
imci_enable_fts_pruner | Global / Session | Whether to enable pre-filtering optimization for inverted indexes.
|
imci_convert_like_to_match | Global / Session | Whether to enable converting
|
imci_enable_query_fts_like | Global / Session | Whether to enable converting
|
imci_enable_match_expr_fallback | Global / Session | Whether to enable queries on incremental data that has not yet been indexed by the inverted index.
|
imci_fts_build_fts_cnt | Global | Number of concurrent inverted index build threads. Valid range: 0-512. Default value: 4. Note This parameter is only applicable to the following versions:
|
imci_fts_user_dict_table | Global | Configures the custom dictionary for full-text indexes. Format: database_name/table_name. Note This parameter is only applicable to the following versions:
|
imci_fts_user_dict_update | Global | Whether to reload the custom dictionary specified by
Note This parameter is only applicable to the following versions:
|
imci_convert_json_overlap_to_match | Global/Session | Controls whether to enable
|
imci_convert_json_contains_to_match | Global/Session | Controls whether to enable
|
imci_convert_json_extract_to_match | Global/Session | Controls whether to enable
|
imci_convert_equal_to_match | Global/Session | Controls whether to enable
|
imci_convert_in_to_match | Global/Session | Controls whether to enable
|
imci_convert_ne_to_match | Global/Session | Controls whether to enable
|
imci_enable_fts_synonym | Global / Session | Whether to support synonyms.
|
imci_enable_fts_parse_term_with_and | Global / Session | Whether to use
|
imci_enable_fts_parse_term_with_phrase | Global / Session | Whether to enforce strict positional matching for tokenized query strings in
|
imci_fts_stop_word_table | Global | Configures the custom stop words for full-text indexes. Format: |
imci_fts_stop_word_update | Global | Whether to reload the custom stop words specified by
|
imci_fts_synonym_table | Global | Configures the custom synonyms for full-text indexes. Format: |
imci_fts_synonym_update | Global | Whether to reload the custom synonyms specified by
|
Parameters with a GLOBAL scope cannot be directly modified from the command line. They can only be changed through the console. When executed from the command line, the default scope is SESSION.
Custom dictionary
The IMCI full-text index feature supports custom dictionaries through custom tables to achieve tokenization results that better match your business scenarios.
Create a custom dictionary table
First, define a table with the same structure as the my_fts_dict table. Column names must match those of the my_fts_dict table.
type: Tokenizer type. Only the jieba tokenizer (type 2) and the IK tokenizer (type 3) are supported.
word: The dictionary word.
is_added: Add the word to the custom dictionary (value 1) or remove it (value 2).
CREATE TABLE my_fts_dict ( `type` INT UNSIGNED NOT NULL COMMENT '2 for jieba, 3 for ik', `word` VARCHAR(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'dict word', `is_added` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1 for add, 2 for delete' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='imci fts user dict';The custom dictionary itself is an InnoDB table. Read and write operations are the same as those for a regular table.
Add a word:
INSERT INTO my_fts_dict VALUES(2, "PolarDB", 1)Remove a word:
INSERT INTO my_fts_dict(type, word, is_added) VALUES(2, "PolarDB", 2); or DELETE FROM my_fts_dict WHERE type=2 AND word = "PolarDB";
Configure the custom dictionary
After creating the custom dictionary table, configure the
imci_fts_user_dict_tableparameter. For example,test/my_fts_dict'.SET GLOBAL imci_fts_user_dict_table = 'test/my_fts_dict';If
imci_fts_user_dict_tableis already set, you can also setimci_fts_user_dict_updateto ON to trigger a reload of the custom dictionary specified byimci_fts_user_dict_table.SET GLOBAL imci_fts_user_dict_update = ON;NoteThe new custom dictionary only takes effect on subsequently built inverted indexes. To apply it to existing inverted indexes, you must rebuild the inverted indexes.
Custom synonyms
The IMCI full-text index feature supports custom synonyms through custom tables.
Create a custom synonym table
First, define a table with the same structure as the my_synonym_dict table. Column names must match those of the my_synonym_dict table.
word: The synonym list. Different words are separated by commas.type: The synonym type.0indicates that all words in the list are synonyms of each other. For example,"db,database,polardb"means"db" <=> "database" <=> "polardb". When you search for"db","database", or"polardb", all data matching"db","database", and"polardb"is returned.1indicates that the first word in the list is the primary term and the others are its synonyms. For example,"db,database,polardb"means"db" => "database", "polardb". When you search for"db", all data matching"db","database", and"polardb"is returned. However, when you search for"database", only data matching"database"is returned.
CREATE TABLE my_synonym_dict (
`word` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'comma-separated synonyms',
`type` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0 for equivalent, 1 for mapping'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='imci fts synonym';The custom synonym table itself is an InnoDB table. Read and write operations are the same as those for a regular table.
Add a word:
INSERT INTO my_synonym_dict VALUES("db,database,polardb", 0); INSERT INTO my_synonym_dict VALUES("imci,clickhouse,duckdb", 1);Remove a word:
DELETE FROM my_synonym_dict WHERE type=1 AND word = "imci,clickhouse,duckdb";
Configure custom synonyms
After creating the custom synonym table, configure the imci_fts_synonym_table parameter. For example, test/my_synonym_dict, where test is the database name and my_synonym_dict is the table name.
SET GLOBAL imci_fts_synonym_table = 'test/my_synonym_dict';If imci_fts_synonym_table is already set, you can also set imci_fts_synonym_update to ON to trigger a reload of the custom synonyms specified by imci_fts_synonym_table.
SET GLOBAL imci_fts_synonym_update = ON;If synonym is set to index mode (e.g., COMMENT "imci_fts(type=0 synonym=1)"), updated synonyms only take effect on newly indexed data. To apply the changes to all data, you must rebuild the full-text index.
Custom stop words
The IMCI full-text index feature supports custom stop words through custom tables.
Create a custom stop word table
First, define a table with the same structure as the my_stop_words table. Column names must match those of my_stop_words.
word: The stop word.is_added: Add the word to the custom dictionary (value 1) or remove it (value 0).
CREATE TABLE my_stop_words (
`word` VARCHAR(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'stop word',
`is_added` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1 for add, 0 for delete'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='imci fts stop word';The custom stop word table itself is an InnoDB table. Read and write operations are the same as those for a regular table.
Add a word:
INSERT INTO my_stop_words VALUES("am", 1); INSERT INTO my_stop_words VALUES("chinese", 1);Remove a word:
INSERT INTO my_stop_words(word, is_added) VALUES("chinese", 0); -- or DELETE FROM my_stop_words WHERE is_added=1 AND word = "chinese";
Configure custom stop words
After creating the custom stop word table, configure the imci_fts_stop_word_table parameter. For example, test/my_stop_words, where test is the database name and my_stop_words is the table name.
SET GLOBAL imci_fts_stop_word_table = 'test/my_stop_words';If imci_fts_stop_word_table is already set, you can also set imci_fts_stop_word_update to ON to trigger a reload of the custom stop words specified by imci_fts_stop_word_table.
SET GLOBAL imci_fts_stop_word_update = ON;The new custom stop words only take effect on subsequently built inverted indexes. To apply them to existing inverted indexes, you must rebuild the inverted indexes.
FAQ
Q1: How do I choose the right tokenizer?
English or formatted text: Use the default
type=0(token), which splits by spaces and punctuation.Precise Chinese search: Use the default mode of
type=2(jieba) ortype=3(ik).JSON content search: Use
type=4(json) with theexprparameter to specify the JSON path to index.You can preview how different tokenizers process text using the dbms_imci.fts_tokenize function.
Q2: Why isn't my query using the full-text index?
Make sure
SET imci_enable_fts_query = ON;has been executed. This is the most common cause.Check the
EXPLAINoutput and verify whether theFtsTableScanoperator is present. If not, the query pattern may not match the index, or the system may have determined that a full table scan has a lower cost.
Q3: What is the difference between LIKE queries and MATCH...AGAINST?
LIKE '%keyword%'without a full-text index causes a full table scan, resulting in poor performance. Even when accelerated by IMCI, its functionality is relatively limited.MATCH...AGAINSTis syntax specifically designed for full-text search. It delivers high performance and will support more advanced features such as Boolean queries and relevance scoring in the future. We recommend usingMATCH...AGAINSTfor new applications.