基本概念

什么是分词?

分词就是将一个文本转化成为一系列的单词的过程,也叫文本分析,在 ElasticSearch 中称之为 Analysis。
默认是使用标准分词。
举例:我是中国人 --> 我/是/中国人

分词 api

指定分词器进行分词

分词测试

POST:127.0.0.1:9200/_analyze

1、英文分词

{
"analyzer":"standard",
"text":"hello world"
}

返回值:

{
"tokens": [
{
"token": "hello",
"start_offset": 0,
"end_offset": 5,
"type": "",
"position": 0
},
{
"token": "world",
"start_offset": 6,
"end_offset": 11,
"type": "",
"position": 1
}
]
}

2、中文分词

{
"analyzer": "standard",
"text": "我是中国人"
}

返回值:分为5个词、并不合理。

{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "",
"position": 0
},
{
"token": "是",
"start_offset": 1,
"end_offset": 2,
"type": "",
"position": 1
},
{
"token": "中",
"start_offset": 2,
"end_offset": 3,
"type": "",
"position": 2
},
{
"token": "国",
"start_offset": 3,
"end_offset": 4,
"type": "",
"position": 3
},
{
"token": "人",
"start_offset": 4,
"end_offset": 5,
"type": "",
"position": 4
}
]
}

3、指定索引,字段分词

POST:127.0.0.1:9200/test/_analyze

{
"analyzer": "standard",
"field": "hobby",
"text": "我是中国人"
}

中文分词

1、释义

中文分词的难点在于,在汉语中没有明显的词汇分界点,如在英语中,空格可以作为分隔符。如果分隔不正确就会造成歧义。

如:
我/爱/炒肉丝
我/爱/炒/肉丝
常用中文分词器, IK、jieba、 THULAC等,推荐使用IK分词器。

分词地址:
https://github.com/medcl/elasticsearch-analysis-ik

2、安装 ik 分词器

自动安装

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.1/elasticsearch-analysis-ik-7.8.1.zip

手动安装

将下载到的 elasticsearch-analysis-ik-7.8.1. zip 解圧到 /elasticsearch/plugins/ik 目录下
1 mkdir es/plugins/ik
2 cp elasticsearch-analysis-ik-7.8.1.zip ./es/plugins/ik
3 unzip elasticsearch-analysis-ik-7.8.1.zip
4 ./bin/elasticsearch

3、测试是否安装成功

POST:127.0.0.1:9200/_analyze

{
"analyzer": "ik_max_word",
"text": "我是中国人"
}

返回结果:
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "是",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
},
{
"token": "中国人",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 2
},
{
"token": "中国",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 3
},
{
"token": "国人",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 4
}
]
}

全文搜索

1、全文搜索两个最重要的方面:

1、相关性( Relevance )它是评价查询与其结果间的相关程度,并根据这种相关程度对结果排名的一种能力,这种计算方式可以是TF/IDF方法、地理位置邻近、模糊相似,或其他的某些算法。
2、分词( Analysis )它是将文本块转换为有区别的、规范化的token的一个过程,目的是为了创建倒排索引以及查询倒排索引。

2、重置索引的分词

PUT:127.0.0.1:9200/study

{
"settings": {
"index": {
"number_of_shards": "2",
"number_of_replicas": "0"
}
},
"mappings": {
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "text"
},
"age": {
"type": "integer"
},
"mail": {
"type": "keyword"
},
"desc": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}

3、数据添加

POST:127.0.0.1:9200/study/_doc/_bulk

{ "create": { "_index": "study","_type": "_doc", "_id": "1001" }}
{ "id": 1001,"name": "1001","age": 11,"sex": "女", "desc": "指尖轻触玻窗,嗤嗤的响声,惊动了脆弱的心脏,一阵阵的酸楚,像浪潮般袭来,若果这样酸酸的痛可以代替撕心裂肺,那就让他长久点,这样时间会把我忘记,这样便可躲在这里,让那些软弱手舞足蹈,让那些脆弱和不堪拼命娱乐,让那颗紧绷的心,少少松弦。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1002" }}
{ "id": 1002,"name": "1002","age": 12,"sex": "女", "desc": "曾过往,伊颜纯美无暇,如玉般璀璨,许多人像发现了财富,紧抱于怀,怜香般害怕失去。那时,遇见你的是洗礼过后的悔过者,只懂怜香,而不懂惜玉,再璀璨也掩盖不了他身上久积的灰尘,铸造不了你,也成就不了他,于是乎,迷糊坚固了戏剧化的情谊,疼只是简单的疼。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1003" }}
{ "id": 1003,"name": "1003","age": 13,"sex": "女", "desc": "岁月还远,徐徐的风吹着,却也有了几分萧瑟,春天,不仅有满天飘飞的花儿,还有到处弥散着花的幽香。随着秋韵渐渐浓郁起来,院子里的花便盛开了,整个院子里香气四溢,溢漫着甜丝丝的味儿。金灿的花儿一串串、一撮撮,重重叠叠簇涌着点缀在茂密的绿叶之间,温温暖暖象极了一个个孩子的笑脸,仿佛是给这温暖的春天注入了一道亮丽的风景。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1004" }}
{ "id": 1004,"name": "1004","age": 14,"sex": "女", "desc": "樱花有单樱和双樱,她们绽放时满树灿烂,清香扑鼻,单樱白的如雪如云,双樱色彩如火似霞。但是无论是单樱还是双樱,她们盛开的时间都不长,二十多天的光景,开的绚丽多彩、满树烂漫,落得星星瓣瓣,匆匆忙忙。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1005" }}
{ "id": 1005,"name": "1005","age": 15,"sex": "女", "desc": "真正的相爱,是人在千里,却梦魂相依;真正的相爱,是岁月流转,却不离不弃;真正的相爱,是彼此付出,却无怨无悔。" }

单词搜索

POST: 127.0.0.1:9200/study/_doc/_search

{
"query":{
"match": {
"desc": "时光"
}
}
}

过程说明

1.检查字段类型
描述字段 desc 是一个text类型(指定了IK分词器), 这意味着查询字符串本身也应该被分词。
2.分析查询字符串.
将查询的字符串“音乐传入IK分词器中,输出的结果是单个项音乐。因为只有一个单词项,所以match查询执行的是单个底层term查询。
3.查找匹配文档。
用term查询在倒排索引中查找“音乐”然后获取-组包含该项的文档。
4.为每个文档评分。
用term查询计算每个文档相关度评分. score ,这是种将词频( term frequency ,即词“时光"在相关文档的 desc 字段中出现的频率)和反向文档频率t inverse document frequency ,即词“时光"在所有文档的 desc 字段中出现的频率) , 以及字段的长度(即字段越短相关度越高)相结合的计算方式。

多词搜索

POST: 127.0.0.1:9200/study/_doc/_search

{
"query":{
"match": {
"desc": "时光 岁月"
}
}
}

1、operator

可以发现结果中,包含了 "时光"、 "岁月"的数据都已经被搜索到了。
可是,搜索的结果并不是我们的预期,因为我们想要的是即包含"时光",又包含"岁月"的用户,显然结果返回的是 或者 的关系。
在 ElasticSearch 中可以通过 operator 指定分词之间的逻辑关系, 默认是 or, 具体如下:

POST: 127.0.0.1:9200/study/_doc/_search

{
"query": {
"match": {
"desc": {
"query": "时光 岁月",
"operator": "and"
}
}
}
}

2、最小匹配度 minimum_should_match

前面我们测试了"OR"和“AND"搜索,这是两个极端,其实在实际场景中, 并不会选取这2个极端,更有可能是选取这种,或者说,只需要符合一定的相似度就可以查询到数据;
match 查询还支持 minimum_should_match 最小匹配参数,这个可以指定必须匹配的词项数用来表示一个文档是否相关。
我们可以将其设置为一个具体的数字,通常的做法是将其设置为一个百分数:如: 70% ;

POST: 127.0.0.1:9200/study/_doc/_search

{
"query": {
"match": {
"desc": {
"query": "时光 岁月",
"minimum_should_match": "50%"
}
}
}
}

相似度应该多少合适呢?需要在实际的需求中进行反复测试,才可以得到合理的值。

组合搜索

POST: 127.0.0.1:9200/study/_doc/_search

{
"query": {
"bool": {
"must": {
"match": {
"desc": "时光"
}
},
"must_not": {
"match": {
"desc": "日子"
}
},
"should": [
{
"match": {
"desc": "岁月"
}
}
]
}
}
}

上面搜索的意思是:
搜索结果中必须包含时光,不能包含日子,如果包含了岁月,那么他的相似度会更高。

评分的计算规则:
bool查询会为每一个文档计算相关度评分 _score, 在将所有匹配的 must 和 should 语句的分数 _score 求和。
最后除以 must 和 should 语句的总数。
must_not 语句不会影响评分;他的作用只是将不相关的文档排除。

默认情况下,should 中的内容不是必须匹配的,如果查询语句中没有 must,那么就会至少匹配其中一个。
当然也可以通过 minimum_should_match 参数进行控制,该值可以数字。也可以是百分比。

权重 boost

有些时候,我们可能需要对某些词增加权重来影响该条数据的评分。

搜索关键字为"时光 岁月", 如果包含了"日子" 权重为10,如果包含了"还远"权重为2。

POST: 127.0.0.1:9200/study/_doc/_search

{
"query": {
"bool": {
"must": {
"match": {
"desc": {
"query": "时光 岁月",
"operator": "and"
}
}
},
"should": [
{
"match": {
"desc": {
"query": "日子",
"boost": 10
}
}
},
{
"match": {
"desc": {
"query": "还远",
"boost": 2
}
}
}
]
}
}
}

posted on 2020-08-07 01:18  啥也不会的程序猿  阅读(1647)  评论(0)    收藏  举报