全文搜索是ES的关键特性之一,平时我们使用SQL的like语句,搜索一些文本、字符串是否包含指定的关键词,但是如果两篇文章,都包含我们的关键词,具体那篇文章内容的相关度更高? 这个SQL的like语句是做不到的,更别说like语句的性能问题了。
ES通过分词处理、相关度计算可以解决这个问题,ES内置了一些相关度算法,大体上思想就是,
如果一个关键词在一篇文章出现的频率高,并且在其他文章中出现的少,那说明这个关键词与这篇文章的相关度很高。
分词的目的:
主要就是为了提取搜索关键词,理解搜索的意图,我们平时在百度搜索内容的时候,输入的内容可能很长,但不是每个字都对搜索有帮助,所以通过分词算法,我们输入的搜索关键词,会进一步分解成多个关键词,例如:搜索输入 “上海陆家嘴在哪里?”,分词算法可能分解出:“上海、陆家嘴、哪里”,具体会分解出什么关键词,跟具体的分词算法有关。
默认情况下,使用全文搜索很简单,只要将字段类型定义为
text类型
,然后用
match语句
匹配即可。
ES对于text类型的字段,在插入数据的时候,会进行分词处理,然后根据分词的结果索引文档,当我们搜索text类型字段的时候,也会先对搜索关键词进行分词处理、然后根据分词的结果去搜索。
ES默认的分词器是
standard
,对英文比较友好,
例如:hello world 会被分解成 hello和world两个关键词,如果是中文会分解成一个一个字,例如:上海大学 会分解成: 上、海、大、学。
在ES中,我们可以通过下面方式测试分词效果:
语法:
GET /_analyze
{
"text": "需要分词的内容",
"analyzer": "分词器"
}
例如:
GET /_analyze
{
"text": "hello wolrd",
"analyzer": "standard"
}
使用standard分词器,对hello world进行分词,下面是输出结果:
{
"tokens" : [
{
"token" : "hello",
"start_offset" : 0,
"end_offset" : 5,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "wolrd",
"start_offset" : 6,
"end_offset" : 11,
"type" : "<ALPHANUM>",
"position" : 1
}
]
}
token就是分解出来的关键词。
下面是对中文分词的结果:
GET /_analyze
{
"text": "上海大学",
"analyzer": "standard"
}
输出
{
"tokens" : [
{
"token" : "上",
"start_offset" : 0,
"end_offset" : 1,
"type" : "<IDEOGRAPHIC>",
"position" : 0
},
{
"token" : "海",
"start_offset" : 1,
"end_offset" : 2,
"type" : "<IDEOGRAPHIC>",
"position" : 1
},
{
"token" : "大",
"start_offset" : 2,
"end_offset" : 3,
"type" : "<IDEOGRAPHIC>",
"position" : 2
},
{
"token" : "学",
"start_offset" : 3,
"end_offset" : 4,
"type" : "<IDEOGRAPHIC>",
"position" : 3
}
]
}
明显被切割成一个个的字了。
中文关键词被分解成一个个的字的主要问题就是搜索结果可能不太准确。
例如:
搜索:上海大学
分词结果:上、海、大、学
下面的内容都会被搜到:
上海大学
海上有条船
上海有好吃的
这条船又大又好看
基本上包含这四个字的内容都会被搜到,区别就是相关度的问题,这里除了第一条是相关的,后面的内容基本上跟搜索目的没什么关系。