MySQL 全文索引失效之谜

现象:

在 MySQL 中存在一张数据量较大的表,由于需要使用模糊查询,即“%xxx%”模式,所以创建了全文索引。该表字段的值如下:圆生园;¥圆园;圆生;生园;…圆生;圆生…;…生园;生园…。然而,当使用“SELECT * FROM my_table WHERE MATCH(column) AGAINST(‘+生园’ IN BOOLEAN MODE);”进行查询时,却无法得到结果。

原因:

究其根本原因,是分号“;”对 N-gram 分词逻辑产生了干扰,使得“生园”未能被正确识别为独立的词汇。通过将分隔符进行替换,并重新构建索引,便可以确保全文索引能够按照预期正常工作。

解决方案:通过停用词表忽略分号

由于字段值无法修改,可以通过将分号;加入停用词表(Stopwords)来强制全文索引忽略分号,从而避免分号干扰分词结果。以下是具体步骤:

步骤 1:创建自定义停用词表

  1. 新建停用词表:
    在数据库中创建一个表,用于存储自定义停用词(如分号;):
CREATE TABLE custom_stopwords (value VARCHAR(30)) ENGINE = INNODB;
INSERT INTO custom_stopwords (value) VALUES (';');
-- 若数据中有其他干扰符号(如¥、…),需一并加入停用词表
INSERT INTO custom_stopwords (value) VALUES ('¥'), ('…');
  1. 配置MySQL使用该停用词表:
    修改MySQL全局配置,指向自定义停用词表:
SET GLOBAL innodb_ft_server_stopword_table = 'your_database_name/custom_stopwords';

注:需确保用户有权限修改全局变量。

步骤 2:重建全文索引

  1. 删除旧索引:
ALTER TABLE my_table DROP INDEX index_name;
  1. 创建新索引(忽略分号):
ALTER TABLE my_table 
ADD FULLTEXT INDEX index_name(column) 
WITH PARSER ngram;
  1. 强制更新索引缓存:
OPTIMIZE TABLE tm_info;

步骤 3:查询验证

SELECT * FROM my_table WHERE MATCH(column) AGAINST('+"生园"' IN BOOLEAN MODE);

注:+“生园” 表示必须精确包含“生园”。

关键配置说明

配置项作用配置项
custom_stopwords存储自定义停用词(如分号)需提前创建并插入数据
innodb_ft_server_stopword_table指定全局停用词表需重启或权限生效
ngram_token_size控制分词长度(默认2)若需匹配单字,可设为1
<think>嗯,我现在需要了解ElasticSearch是如何将导入的文档索引化的。我之前对ElasticSearch有一些基本的了解,但具体到索引化的过程可能还不够深入。让我先回忆一下,ElasticSearch是一个基于Lucene的搜索引擎,主要用于全文搜索、结构化搜索和分析。它的核心功能之一就是能够高效地索引和搜索大量数据。 首先,用户可能需要将文档导入到ElasticSearch中,然后这些文档会被索引化。索引化的过程可能涉及到几个步骤:文档的解析、分析、创建倒排索引等等。但具体每个步骤是怎么进行的呢?比如,当用户通过API发送一个文档到ElasticSearch时,ElasticSearch会如何处理这个文档? 我记得在ElasticSearch中,文档是以JSON格式存储的。当文档被发送到某个索引时,ElasticSearch会为这个文档分配一个唯一的ID,并且将其存储在相应的分片中。分片是索引的一部分,可以分布在不同的节点上,提高可用性和性能。但索引化的具体过程可能发生在分片层面? 接下来,可能需要考虑分析过程。分析是将文本转换成一系列词项(terms)的过程,比如分词、去除停用词、转换为小写等。这个过程由分析器(Analyzer)完成,包括字符过滤器、分词器和词项过滤器。例如,对于英文文本,分析器可能会将句子拆分成单词,去掉“and”、“the”这样的停用词,并将所有字母转为小写,以便于搜索时匹配。 那倒排索引又是如何构建的呢?倒排索引是Lucene的核心数据结构,它记录了每个词项出现在哪些文档中,以及出现的位置和频率。当文档被分析后,每个字段的内容会被处理成词项,然后这些词项被添加到倒排索引中,指向原始文档。这样在搜索时,ElasticSearch可以快速找到包含特定词项的文档。 不过,可能还有一些细节需要注意,比如动态映射和显式映射的区别。当用户第一次向索引中添加文档时,如果索引不存在,ElasticSearch会自动创建索引,并根据文档字段的数据类型推断映射(Mapping)。映射定义了字段的类型(如文本、关键字、数值等)以及使用的分析器。但自动推断可能不总是符合需求,因此有时需要显式定义映射,以确保字段被正确处理。 此外,索引操作可能分为两种:实时和近实时。ElasticSearch使用写操作缓冲区(In-memory buffer)和事务日志(Translog)来保证数据的持久性。当文档被索引时,首先会被写入内存缓冲区,并记录到Translog中。默认情况下,索引操作在1秒后刷新(refresh),使文档可被搜索,这属于近实时搜索。而更持久的提交(commit)操作则会定期将内存中的数据写入磁盘段中,同时清除Translog。 还有,段(Segments)的概念。Lucene索引由多个不可变的段组成,每次刷新都会生成一个新段。段合并(Merge)过程会将这些小段合并成大段,优化查询性能并释放空间。合并过程中,旧段被删除,新段被创建,这个过程可能会影响性能,但有助于长期效率。 总结一下,索引化的流程可能包括以下步骤: 1. 客户端发送文档到ElasticSearch的某个索引。 2. 如果索引不存在,自动创建并根据文档结构推断映射。 3. 文档被分析处理,生成词项。 4. 构建倒排索引,将词项与文档关联。 5. 文档存储在分片中,通过Translog保证数据安全。 6. 定期刷新使文档可搜索,段合并优化索引结构。 不过,我可能忽略了一些细节,比如如何处理嵌套文档或父子关系?或者地理空间数据?这些可能需要特殊的映射和分析处理。另外,集群环境下,分片如何分布和复制?主分片和副本分片在索引过程中的角色? 再考虑一下错误处理,比如如果文档中的某个字段不符合映射定义,会发生什么?比如试图将字符串存入日期字段,ElasticSearch会抛出异常还是忽略?这取决于动态映射的设置,如果动态映射设置为strict,则会拒绝文档;如果是true或false,可能会有不同行为。 最后,索引性能优化方面,比如批量插入(Bulk API)的使用,调整刷新间隔,分片数量设置等都可能影响索引化的效率和资源消耗。</think>ElasticSearch 索引化文档的过程涉及多个步骤,从数据接收到最终可搜索的存储,以下是详细流程: --- ### **1. 文档接收与路由** - **写入请求**:客户端通过 REST API(如 `PUT` 或 `POST`)将文档(JSON 格式)发送到指定索引。 - **路由分配**:根据文档 ID 或自定义路由规则,确定文档应存储在哪个分片(主分片)。计算公式:`shard_num = hash(_routing) % num_primary_shards`。 --- ### **2. 动态映射与显式映射** - **映射(Mapping)定义**: - **动态映射**:若索引不存在,ElasticSearch 自动创建并推断字段类型(如文本转为 `text`,数字转为 `long`)。 - **显式映射**:用户可预先定义字段类型(如 `keyword`、`date`)和分析器,避免自动推断不准确。 - **字段类型影响**:`text` 字段会被分词,而 `keyword` 字段保留原始值用于精确匹配。 --- ### **3. 文档分析与处理** - **分析器(Analyzer)工作流程**: 1. **字符过滤**:处理原始文本(如去除 HTML 标签)。 2. **分词**:按规则拆分文本为词项(如空格分词)。 3. **词项过滤**:转换大小写、移除停用词(如 "the")、添加同义词等。 - **示例**:句子 "Quick Brown Foxes" 可能被处理为词项 `["quick", "brown", "fox"]`。 --- ### **4. 构建倒排索引** - **倒排索引结构**:记录每个词项对应的文档列表及位置信息。 - 词项 → 文档 ID、词频、偏移量等。 - **存储方式**:数据写入内存缓冲区,并记录到事务日志(Translog)以保证持久性。 --- ### **5. 刷新(Refresh)与段(Segment)生成** - **近实时搜索**:默认每 1 秒执行一次刷新,将内存缓冲区数据生成新的 Lucene 段,使其可被搜索。 - **段特性**:不可修改,查询时合并结果。频繁刷新会增加段数量,可能影响性能。 --- ### **6. 事务日志(Translog)与持久化** - **容错机制**:所有操作记录到 Translog,防止数据丢失。 - **刷新到磁盘**:定期执行 `fsync` 将内存数据写入磁盘,清空 Translog(默认每 30 分钟或 Translog 过大时触发)。 --- ### **7. 段合并(Merge)** - **后台优化**:多个小段合并为大段,提升查询效率并释放磁盘空间。 - **合并策略**:由 Lucene 自动管理,可配置合并策略(如 `tiered`)。 --- ### **8. 分片复制与高可用** - **副本分片同步**:主分片写入成功后,数据并行复制到副本分片,确保高可用性。 - **写入流程**:遵循 `wait_for_active_shards` 参数控制一致性级别(如需多数分片确认)。 --- ### **关键优化点** - **批量写入**:使用 `Bulk API` 减少请求开销。 - **调整刷新间隔**:增大 `refresh_interval` 减少段生成频率,提升写入速度。 - **合理分片数**:避免过多分片导致资源竞争(通常单个分片大小建议 10-50GB)。 --- 通过以上步骤,ElasticSearch 将原始文档转换为高效、可搜索的索引结构,平衡了写入性能与查询实时性。开发者需根据场景调整映射、分析器和集群参数以优化效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值