前言
ES 最重要的能力莫过于通过分词能力,实现全文搜索和模糊查询了,要想搭建一个强大的搜索引擎,分词是关键,下面会剖析下 ES 的分词规则以及使用案例,带你从零入门 ES 搜索。
当然前提字段类型必须是 text,分词才会生效。
分词器有哪些类型
1. standard
- 描述:这是Elasticsearch的默认分词器,基于Unicode文本分割算法,将文本分割成单词。
- 适用场景:适用于大多数西方语言。
2. keyword
- 描述:将整个输入作为一个单独的标记(token)。
- 适用场景:适用于不需要分词的字段,如ID、电子邮件地址等。
3. whitespace
- 描述:仅根据空格来分割文本。
- 适用场景:适用于那些主要通过空格分隔单词的语言或特定格式的文本。
4. pattern
- 描述:使用正则表达式来定义如何分割文本。
- 适用场景:适用于需要自定义分割规则的复杂场景。
5. uax_url_email
- 描述:专门用于处理包含电子邮件地址和URL的文本,能够识别并正确分割这些特殊结构。
- 适用场景:适用于需要解析电子邮件和URL的场景。
6. path_hierarchy
- 描述:将路径字符串(如文件系统路径)分解成层次结构的标记。
- 适用场景:适用于需要按路径层级搜索的场景,如文件管理系统。
7. ngram
- 描述:生成输入文本的所有可能的n-gram序列作为标记。
- 适用场景:适用于需要模糊匹配或全文搜索的场景,特别是亚洲语言的处理。
8. edge_ngram
- 对应类:
org.apache.lucene.analysis.ngram.EdgeNGramTokenizerFactory
- 描述:类似于N-gram分词器,但只生成从文本开头开始的n-gram序列。
- 适用场景:适用于自动补全和建议功能。
9. icu_tokenizer
- 对应类:
com.ibm.icu.lucene.tokenizer.ICUTokenizerFactory
- 描述:使用ICU库进行分词,支持Unicode标准和各种语言的特性。
- 适用场景:适用于需要国际化支持的多语言环境。
10. kstem
- 对应类:
org.apache.lucene.analysis.en.KStemTokenizerFactory
- 描述:Krovetz Stemming算法的实现,主要用于英文文本。
- 适用场景:适用于需要英文词干提取的场景。
11. mmseg
- 对应类:
org.elasticsearch.index.analysis.MMSEGTokenizerFactory
- 描述:用于中文分词的MMSEG算法实现。
- 适用场景:适用于中文文本的分词。
12. smartcn
- 对应类:
org.elasticsearch.index.analysis.SmartCnTokenizerFactory
- 描述:Smart Chinese Analysis Plugin提供的中文分词器。
- 适用场景:适用于中文文本的分词。
过滤器(Filters)
除了分词器之外,Elasticsearch还提供了多种过滤器来进一步处理分词结果:
- 小写过滤器(lowercase):将所有标记转换为小写。
- 停用词过滤器(stop):移除常见的无意义词汇(如“and”、“is”、“the”等)。
- 同义词过滤器(synonym):将标记替换为其同义词。
- 词干提取过滤器(stemmer):将单词还原为其词根形式。
- 字符映射过滤器(mapping):根据预定义的映射规则替换或删除标记。
在实际应用中,通常会组合使用分词器和过滤器来达到最佳的分词效果。例如,一个常见的组合是使用标准分词器配合小写过滤器和停用词过滤器,以实现基本的文本处理需求。
示例配置
使用自定义分词器
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "stop"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "custom_analyzer"
}
}
}
}
在这个示例中,custom_analyzer
使用了标准分词器,并通过小写和停用词过滤器对分词结果进行了进一步处理。
当然也可以直接指定分词器
PUT /my_index
{
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "standard"
}
}
}
}
如果索引已经存在,可以使用以下方式来更新字段的分词器:
PUT /my_index/_mapping
{
"properties": {
"content": {
"type": "text",
"analyzer": "custom_analyzer"
}
}
}
请注意,更新映射并不会改变已经索引的数据,只会影响新添加的数据。
完整示例
创建索引并指定分词器,使用PUT
请求来创建一个新的索引,并在索引的设置中定义分词器
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "stop"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "custom_analyzer"
}
}
}
}
验证分词器
可以使用 _analyze
API 来验证分词器的工作效果:
POST /my_index/_analyze
{
"analyzer": "custom_analyzer",
"text": "This is a test sentence."
}
这个请求会返回分词后的结果,帮助你确认分词器是否按预期工作。
更新现有索引的分词器
如果你需要更新现有索引的分词器,可以使用 _update_by_query
API 来重新索引数据,或者创建一个新的索引并重新索引数据。
重新索引数据
PUT /my_index_v2
{
"settings": {
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "stop"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "custom_analyzer"
}
}
}
}
使用 _reindex
API 将数据从旧索引复制到新索引:
POST /_reindex
{
"source": {
"index": "my_index"
},
"dest": {
"index": "my_index_v2"
}
}
完成后,你可以删除旧索引并重命名新索引:
DELETE /my_index
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_v2", "alias": "my_index" } },
{ "add": { "index": "my_index_v2", "alias": "my_index" } }
]
}
分词器的性能如何优化
Elasticsearch 分词器的性能优化可以从多个方面进行,以下是一些关键的优化策略:
1. 选择合适的分词器
- 根据数据的特点选择最合适的分词器。例如,对于中文文本,使用 IK 分词器或者结巴分词器会比标准分词器更有效。
2. 减少不必要的分词
- 如果字段不需要全文搜索功能,可以将其设置为
keyword
类型,避免不必要的分词操作。
3. 使用缓存
- Elasticsearch 会对频繁查询的结果进行缓存,确保索引和搜索的缓存设置得当可以显著提高性能。
4. 合理设置分片和副本
- 分片的数量会影响索引和搜索的速度,需要根据数据量和查询负载合理设置。
- 副本可以提高查询的并发能力,但也会增加索引的时间和存储需求。
5. 优化索引设置
- 调整
refresh_interval
来平衡数据的实时性和索引的性能。 - 使用
index.number_of_replicas
和index.number_of_shards
来优化索引的读写性能。
6. 使用批量操作
- 批量索引(Bulk API)可以显著提高索引速度,尽量减少单个文档的索引操作。
7. 避免深分页
- 深分页(Deep Pagination)会导致 Elasticsearch 性能下降,尽量避免使用
from
和size
进行大量数据的翻页。
8. 使用合适的硬件资源
- 确保 Elasticsearch 集群有足够的内存、CPU 和磁盘I/O资源。
9. 监控和调优
- 使用 Elasticsearch 的监控工具,如 Kibana 或 Marvel,来监控集群的健康状况和性能指标。
- 根据监控结果进行针对性的调优。
10. 索引模板和映射优化
- 合理设计索引模板和字段映射,避免不必要的复杂性和冗余。
11. 使用更快的存储
- 使用 SSD 而不是 HDD 可以提高索引和搜索的速度。
12. 优化查询语句
- 编写高效的查询语句,避免使用低效的全文搜索和复杂的聚合操作。
13. 定期重建索引
- 随着数据的增长和变化,定期重建索引可以帮助维持搜索性能。
14. 使用索引别名
- 使用索引别名可以简化索引管理和提高搜索性能。
15. 考虑使用 Elasticsearch 的最新版本
- 新版本通常会包含性能改进和优化,确保使用的是最新的稳定版本。