基本概念

什么是分词?

分词就是将一个文本转化成为一系列的单词的过程,也叫文本分析,在 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": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "world",
            "start_offset": 6,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 1
        }
    ]
}

2、中文分词

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

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

{
    "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
        },
        {
            "token": "人",
            "start_offset": 4,
            "end_offset": 5,
            "type": "<IDEOGRAPHIC>",
            "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": "真正的相爱,是人在千里,却梦魂相依;真正的相爱,是岁月流转,却不离不弃;真正的相爱,是彼此付出,却无怨无悔。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1006" }}

单词搜索

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  啥也不会的程序猿  阅读(1438)  评论(0编辑  收藏  举报