本篇文章主要讲解中文分词和 ElasticSearch 中的重要 API —— Suggester,同时也会提到 Search Template、Index Alias 和 Function Score Query 等高级搜索功能。
自然语言与查询
当处理人类自然语言时,有时尽管搜索和原文不完全匹配,但是希望搜到一些内容。
可以采取的措施:
- 归一化词元:例如消除变音符号(西语,拼音)。
- 抽取词根:消除单复数等。
- 包含同义词。
- 拼写错误处理。
混合多语言的挑战
不同的索引使用不同的语言;同一个索引中,不同的字段使用不同的语言;一个文档的一个字段内混合不同的语言。
- 词干提取:以色列文档,包含了希伯来语,阿拉伯语,俄语和英文。
- 不正确的文档频率:英文为主的文章中,德文算分高(稀有)。
- 需要判断用户搜索时使用的语言。
中文分词(IK)
由于生产环境中最常见的中文分词器为 IK,因此本篇也以 IK 为主。
安装
仓库地址:L2ncE/es101
克隆仓库后进入到 docker-compose 文件 目录,将 docker.elastic.co/elasticsearch/elasticsearch:7.8.0
改为 zingimmick/elasticsearch-ik:7.8.0
。运行 docker-compose up
。
示例
POST _analyze
{
"analyzer": "ik_smart",
"text": ["剑桥分析公司多位高管对卧底记者说,他们确保了唐纳德·特朗普在总统大选中获胜"]
}
Search Template
用于解耦程序和搜索 DSL。
示例
POST _scripts/tmdb
{
"script": {
"lang": "mustache",
"source": {
"_source": [
"title",
"overview"
],
"size": 20,
"query": {
"multi_match": {
"query": "{{q}}",
"fields": [
"title",
"overview"
]
}
}
}
}
}
POST tmdb/_search/template
{
"id":"tmdb",
"params": {
"q": "basketball with cartoon aliens"
}
}
上游可以不感知模版的变化,避免耦合。
Index Alias
实现零停机运维。比如在进行索引重建、版本升级、滚动更新等操作时,无需中断服务。
示例
1、插入数据
PUT movies-2019/_doc/1
{
"name":"the matrix",
"rating":5
}
PUT movies-2019/_doc/2
{
"name":"Speed",
"rating":3
}
2、设置别名
POST _aliases
{
"actions": [
{
"add": {
"index": "movies-2019",
"alias": "movies-latest"
}
}
]
}
POST movies-latest/_search
{
"query": {
"match_all": {}
}
}
Function Score Query
可以在查询结束后对每一个匹配的文档进行一系列的重新算分,根据新生成的分数进行排序。
- Weight:为每一个文档设置一个简单而不被规范化的权重。
- Field Value Factor:使用该数值来修改
\_score
,例如将「热度」和「点赞数」作为算分的参考因素。 - Random Score: 为每一个用户使用一个不同的,随机算分结果。
- 衰减函数:以某个字段的值为标准,距离某个值越近,得分越高。
- Script Score:自定义脚本完全控制所需逻辑。
示例
1、插入数据
DELETE blogs
PUT /blogs/_doc/1
{
"title": "About popularity",
"content": "In this post we will talk about...",
"votes": 0
}
PUT /blogs/_doc/2
{
"title": "About popularity",
"content": "In this post we will talk about...",
"votes": 100
}
PUT /blogs/_doc/3
{
"title": "About popularity",
"content": "In this post we will talk about...",
"votes": 1000000
}
2、使用多个参数测试
POST /blogs/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "popularity",
"fields": [ "title", "content" ]
}
},
"field_value_factor": {
"field": "votes",
"modifier": "log1p" ,
"factor": 0.1
}
}
}
}
- 初始逻辑:
- 使用 modifier 平滑参数后:
- Factor 参数:
3、一致性随机函数
POST /blogs/_search
{
"query": {
"function_score": {
"random_score": {
"seed": 911119
}
}
}
}
- 使用场景:网站的广告需要提高展现率。
- 具体需求:让每个用户能看到不同的随机排名,但是也希望同一个用户访问时,结果的相对顺序保持一致。
4、Boost Mode 和 Max Boost
POST /blogs/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "popularity",
"fields": [ "title", "content" ]
}
},
"field_value_factor": {
"field": "votes",
"modifier": "log1p" ,
"factor": 0.1
},
"boost_mode": "sum",
"max_boost": 3
}
}
}
Max Boost 可以将算分控制在一个最大值。Boost Mode 用于进行算分的数学运算。
Suggester
实现搜索引擎中纠错的功能。原理是将文本分解为 Token 然后在索引的字典中查找相似的 Term 并返回。
四种 Suggester 的不同之处:
Suggester 类型 | 功能与特点 | 适用场景 |
---|---|---|
Term Suggester | 对输入文本的每个词条进行纠错或建议,基于索引中的词典查找相似 Term。 | 单个词条级别的纠错和建议(如拼写错误修正)。 |
Phrase Suggester | 在 Term Suggester 基础上,考虑多个词条之间的关系(如是否共同出现、相邻程度等)。 | 多个词组成的短语级别的纠错和建议(如句子片段的修正)。 |
Completion Suggester | 提供前缀匹配的自动补全功能,支持快速搜索建议(如用户输入时的提示)。 | 快速自动补全(如搜索框输入提示)。 |
Context Suggester | 基于 Completion Suggester,增加了上下文信息的支持(如地理位置、类别等过滤条件)。 | 需要结合上下文信息的自动补全(如特定分类下的搜索提示)。 |
示例
1、插入数据
DELETE articles
POST articles/_bulk
{ "index" : { } }
{ "body": "lucene is very cool"}
{ "index" : { } }
{ "body": "Elasticsearch builds on top of lucene"}
{ "index" : { } }
{ "body": "Elasticsearch rocks"}
{ "index" : { } }
{ "body": "elastic is the company behind ELK stack"}
{ "index" : { } }
{ "body": "Elk stack rocks"}
{ "index" : {} }
{ "body": "elasticsearch is rock solid"}
2、Term Suggester
几种 Suggestion Mode
- Missing:如果索引中已经存在,就不提供建议。
- Popular:推荐出现频率更加高的词。
- Always:无论是否存在,都提供建议。
POST /articles/_search
{
"size": 1,
"query": {
"match": {
"body": "lucen rock"
}
},
"suggest": {
"term-suggestion": {
"text": "lucen rock",
"term": {
"suggest_mode": "missing",
"field": "body"
}
}
}
}
3、Phrase Suggester
在 Term Suggester 的基础上增加了一些额外的逻辑。
- Max Errors:最多可以拼错的 Terms 数。
- Confidence:控制返回建议的置信度阈值。只有当建议短语的原始得分加上长度归一化后 ≥confidence 时才会被返回,默认为 1。
POST /articles/_search
{
"suggest": {
"my-suggestion": {
"text": "lucne and elasticsear rock hello world ",
"phrase": {
"field": "body",
"max_errors":2,
"confidence":2,
"direct_generator":[{
"field":"body",
"suggest_mode":"always"
}],
"highlight": {
"pre_tag": "<em>",
"post_tag": "</em>"
}
}
}
}
}
4、Completion Suggester
提供了自动补全功能。对性能要求比较严苛,采用了非倒排索引的数据结构,将 Analyze 数据编码成 FST 和索引一起存放。FST 会整个加载进内存,速度很快。同时 FST 仅支持前缀查找。
DELETE articles
PUT articles
{
"mappings": {
"properties": {
"title_completion":{
"type": "completion"
}
}
}
}
POST articles/_bulk
{ "index" : { } }
{ "title_completion": "lucene is very cool"}
{ "index" : { } }
{ "title_completion": "Elasticsearch builds on top of lucene"}
{ "index" : { } }
{ "title_completion": "Elasticsearch rocks"}
{ "index" : { } }
{ "title_completion": "elastic is the company behind ELK stack"}
{ "index" : { } }
{ "title_completion": "Elk stack rocks"}
{ "index" : {} }
POST articles/_search?pretty
{
"size": 0,
"suggest": {
"article-suggester": {
"prefix": "elk ",
"completion": {
"field": "title_completion"
}
}
}
}
5、Context Suggester
是 Completion Suggester 的拓展,能够在搜索中加入更多的上下文信息。
可以定义两种类型的 Context:
- Category 一任意的字符串。
- Geo—地理位置信息。
实现 Context Suggester 的具体步骤:
- 定制一个 Mapping。
- 索引数据,并且为每个文档加入 Context 信息。
- 结合 Context 进行 Suggestion 查询。
DELETE comments
PUT comments
PUT comments/_mapping
{
"properties": {
"comment_autocomplete":{
"type": "completion",
"contexts":[{
"type":"category",
"name":"comment_category"
}]
}
}
}
POST comments/_doc
{
"comment":"I love the star war movies",
"comment_autocomplete":{
"input":["star wars"],
"contexts":{
"comment_category":"movies"
}
}
}
POST comments/_doc
{
"comment":"Where can I find a Starbucks",
"comment_autocomplete":{
"input":["starbucks"],
"contexts":{
"comment_category":"coffee"
}
}
}
POST comments/_search
{
"suggest": {
"MY_SUGGESTION": {
"prefix": "sta",
"completion":{
"field":"comment_autocomplete",
"contexts":{
"comment_category":"coffee"
}
}
}
}
}
写在最后
这是该系列的第六篇,主要讲解中文分词和 ElasticSearch 中的重要 API —— Suggester,同时也提到 Search Template、Index Alias 和 Function Score Query 等高级搜索功能。可以自己去到 Kibana 的 Dev Tool 实战操作,未来会持续更新该系列,欢迎关注👏🏻。
同时欢迎关注公众号:LanTech指南。不定时分享职场思考、独立开发日志、大厂方法论和后端经验❤️