ElasticSearch教程入门到精通------第一部分(基于ELK技术栈elasticsearch 8.x新特性)
- [1. ElasticSearch安装(略)](#1. ElasticSearch安装(略))
- [2. ElasticSearch基础功能](#2. ElasticSearch基础功能)
-
- [2.1 索引操作](#2.1 索引操作)
-
- [2.1.1 创建索引](#2.1.1 创建索引)
- [2.1.2 Head 索引](#2.1.2 Head 索引)
- [2.1.3 查询索引](#2.1.3 查询索引)
-
- [2.1.3.1 查询单独索引](#2.1.3.1 查询单独索引)
- [2.1.3.2 查询全部索引](#2.1.3.2 查询全部索引)
- [2.1.4 增加配置](#2.1.4 增加配置)
- [2.1.5 删除索引](#2.1.5 删除索引)
- [2.2 文档操作](#2.2 文档操作)
-
- [2.2.1 创建文档](#2.2.1 创建文档)
- [2.2.2 查询文档](#2.2.2 查询文档)
-
- [2.2.2.1 查询个别文档](#2.2.2.1 查询个别文档)
- [2.2.2.2 查询文档所有数据](#2.2.2.2 查询文档所有数据)
- [2.2.3 修改数据](#2.2.3 修改数据)
- [2.2.4 删除数据](#2.2.4 删除数据)
- [2.3 文档搜索](#2.3 文档搜索)
-
- [2.3.1 Match分词查询](#2.3.1 Match分词查询)
- [2.3.2 使用term精确匹配某个字段的关键词](#2.3.2 使用term精确匹配某个字段的关键词)
- [2.3.3 查询结果中过滤某些不需要的字段](#2.3.3 查询结果中过滤某些不需要的字段)
- [2.3.4 多条件组合查询](#2.3.4 多条件组合查询)
-
- [2.3.4.1 查询name中含有zhang或age为40的数据](#2.3.4.1 查询name中含有zhang或age为40的数据)
- [2.3.4.2 查询文档中name中必须含有zhang或者age必须大于等于30岁的数据](#2.3.4.2 查询文档中name中必须含有zhang或者age必须大于等于30岁的数据)
- [2.3.4.3 查询结果排序](#2.3.4.3 查询结果排序)
- [2.3.5 分页查询](#2.3.5 分页查询)
- [2.4 聚合搜索](#2.4 聚合搜索)
-
- [2.4.1 根据age将查询结果进行分组聚合](#2.4.1 根据age将查询结果进行分组聚合)
- [2.4.2 查询年龄大于等于40岁的,并将结果按照age分组聚合](#2.4.2 查询年龄大于等于40岁的,并将结果按照age分组聚合)
- [2.4.3 根据age分组聚合,再对聚合后的结果按照age求平均值](#2.4.3 根据age分组聚合,再对聚合后的结果按照age求平均值)
- [2.4.4 获取结果集中的前N个数据](#2.4.4 获取结果集中的前N个数据)
- [2.4.5 获取结果集中按照age字段排序后求取前N个数据](#2.4.5 获取结果集中按照age字段排序后求取前N个数据)
- [2.5 索引模板](#2.5 索引模板)
-
- [2.5.1 创建/修改 索引](#2.5.1 创建/修改 索引)
- [2.5.2 查看模板](#2.5.2 查看模板)
- [2.5.3 更新模板](#2.5.3 更新模板)
- [2.5.4 应用模板](#2.5.4 应用模板)
- [2.5.5 删除模板](#2.5.5 删除模板)
- [2.6 中文分词](#2.6 中文分词)
-
- [2.6.1 分词操作](#2.6.1 分词操作)
- [2.6.2 分词操作(不带插件情况下,中文拆分逻辑太适合)](#2.6.2 分词操作(不带插件情况下,中文拆分逻辑太适合))
- [2.6.3 集成了IK插件后提供的分词](#2.6.3 集成了IK插件后提供的分词)
-
- [2.6.3.1 ik_smart------最少切分](#2.6.3.1 ik_smart——最少切分)
- [2.6.3.2 ik_max_word------最细粒度切分](#2.6.3.2 ik_max_word——最细粒度切分)
- [2.6.4 自定义分词效果](#2.6.4 自定义分词效果)
- [2.7 文档评分机制(转载)](#2.7 文档评分机制(转载))
-
- [2.7.1 TF-IDF 原理](#2.7.1 TF-IDF 原理)
-
- [2.7.1.1 计算公式](#2.7.1.1 计算公式)
- [2.7.1.2 示例说明](#2.7.1.2 示例说明)
- [2.7.1.3 计算TF](#2.7.1.3 计算TF)
- [2.7.1.4 计算IDF](#2.7.1.4 计算IDF)
- [2.7.1.5 TF-IDF计算](#2.7.1.5 TF-IDF计算)
- [2.7.2 Elasticsearch打分机制](#2.7.2 Elasticsearch打分机制)
-
- [2.7.2.1 示例说明](#2.7.2.1 示例说明)
- [2.7.2.2 计算 TF 值](#2.7.2.2 计算 TF 值)
- [2.7.2.3 计算 IDF 值](#2.7.2.3 计算 IDF 值)
- [2.7.2.4 计算文档得分](#2.7.2.4 计算文档得分)
- [2.7.2.5 增加新的文档测试得分](#2.7.2.5 增加新的文档测试得分)
- [2.7.3 案列](#2.7.3 案列)
-
- [2.7.3.1 需求](#2.7.3.1 需求)
- [2.7.3.2 准备数据](#2.7.3.2 准备数据)
- [2.7.3.3 查询数据](#2.7.3.3 查询数据)
1. ElasticSearch安装(略)
-
Kibana 官网安装
2. ElasticSearch基础功能
2.1 索引操作
2.1.1 创建索引
ES软件的索引可以类比为MySQL中表的概念,创建一个索引,类似于创建一个表。查询完成后,Kibana右侧会返回响应结果及请求状态
powershell
PUT test_index
重复创建索引------报错!
2.1.2 Head 索引
powershell
head test_index
powershell
head test_index1
2.1.3 查询索引
2.1.3.1 查询单独索引
powershell
GET test_index
2.1.3.2 查询全部索引
cpp
GET _cat/indices
2.1.4 增加配置
JSON格式的主题内容
json
PUT test_index_1
{
"aliases":{
"test1":{}
}
}
查询看结果
这样 别名就设置上了
powershell
GET test1
试一试~
注意:ES软件不支持修改索引信息,如果想要修改,只能新建
2.1.5 删除索引
powershell
DELETE test_index_1
再删除一次 ~!
2.2 文档操作
文档是ES软件搜索数据的最小单位,不依赖预先定义的模式,所以可以将文档类比为表的一行JSON类型的数据。我们知道关系型数据库中,要提前定义字段才能使用,在Elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
2.2.1 创建文档
索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为JSON格式
powershell
PUT test_doc
添加索引
powershell
PUT test_doc/_doc
{
"id":1001,
"name":"zhangsan",
"age":30
}
为什么只让用Post 不让用PUT?
- 因为PUT创建的时候,创建数据具有唯一性标识
powershell
PUT test_doc/_doc/1001
{
"id":1001,
"name":"zhangsan",
"age":30
}
powershell
POST test_doc/_doc
{
"id":1002,
"name":"lisi",
"age":40
}
2.2.2 查询文档
2.2.2.1 查询个别文档
powershell
GET test_doc/_doc/1001
powershell
GET test_doc/_doc
2.2.2.2 查询文档所有数据
powershell
GET test_doc/_search
2.2.3 修改数据
powershell
PUT test_doc/_doc/1001
{
"id":10011,
"name":"zhangsan1",
"age":300,
"tel":123123
}
POST 也可以
2.2.4 删除数据
powershell
DELETE test_doc/_doc/1002
再删一次
2.3 文档搜索
powershell
PUT test_query
powershell
PUT test_query/_bulk
{"index": {"_index": "test_query","_id": "1001"}}
{"id": "1001","name":"zhang san","age":30}
{"index": {"_index": "test_query","_id": "1002"}}
{"id": "1002","name":"li si","age": 40}
{"index": {"_index": "test_query","_id": "1003"}}
{"id": "1003", "name": "wang wu","age" : 50}
{"index": {"_index": "test_query","_id": "1004"}}
{"id": "1004","name": "zhangsan", "age" : 30}
{"index": {"_index": "test_query","_id": "1005"}}
{"id": "1005","name": "lisi","age":40}
{"index": {"_index": "test_query","_id": "1006"}}
{"id": "1006", "name ": "wangwu","age" : 50}
2.3.1 Match分词查询
Match 是分词查询,ES会将数据分词保存
powershell
GET test_query/_search
{
"query":{
"match":{
"name":"zhangsan"
}
}
}
powershell
GET test_query/_search
{
"query":{
"match":{
"name":"zhang"
}
}
}
powershell
GET test_query/_search
{
"query":{
"match":{
"name":"zhang li"
}
}
}
2.3.2 使用term精确匹配某个字段的关键词
但是我不想分词~
powershell
GET test_query/_search
{
"query":{
"term":{
"name":{
"value":"zhang san"
}
}
}
}
powershell
GET test_query/_search
{
"query":{
"term":{
"name":{
"value":"zhangsan"
}
}
}
}
2.3.3 查询结果中过滤某些不需要的字段
某些情况下,不需要查询结果中返回所有的字段,就可以通过添加"_source"进行限制
powershell
GET test_query/_search
{
"_source": ["name","age"],
"query": {
"match": {
"name": "zhang"
}
}
}
2.3.4 多条件组合查询
组合查询的关键语法是需要在查询条件中使用bool关键字
2.3.4.1 查询name中含有zhang或age为40的数据
这个需求类似于mysql 中的or的语法,在es中使用should可以满足类似的需求
powershell
GET test_query/_search
{
"query": {
"bool": {
"should": [
[
{
"match":{
"name":"zhang"
}
},
{
"match":{
"age":40
}
}
]
]
}
}
}
2.3.4.2 查询文档中name中必须含有zhang或者age必须大于等于30岁的数据
组合使用should和must
powershell
GET test_query/_search
{
"query": {
"bool": {
"must": [
[
{
"match":{
"name":"zhang"
}
}
]
],
"should": [
{
"range": {
"age": {
"gte": 30
}
}
}
]
}
}
}
2.3.4.3 查询结果排序
查询name中含有 zhang的文档,并按照age排序
powershell
GET test_query/_search
{
"query": {
"match": {
"name": "zhang"
}
},
"sort":[
{
"age" : {
"order":"desc"
}
}
]
}
2.3.5 分页查询
语法
powershell
GET 索引名称/_search
{
"query": {
"match_all": {}
},
"from": 0, //从第几条开始查询
"size": 2 //每次查询多少数据
}
看下面的查询结果
计算公式:
f r o m = ( p a g e n o − 1 ) ∗ s i z e from = (pageno -1)*size from=(pageno−1)∗size
2.4 聚合搜索
实际业务中,经常会涉及到对查询的结果根据某个或者某些字段进行聚合,类似于mysql中的group by语法;
2.4.1 根据age将查询结果进行分组聚合
注意点:这里 "size"设置为0表示查询结果中不展示其他非聚合结果的信息;
powershell
GET test_query/_search
{
"aggs": {
"aggAge": {
"terms": {
"field": "age"
}
}
},
"size": 0
}
2.4.2 查询年龄大于等于40岁的,并将结果按照age分组聚合
powershell
GET test_query/_search
{
"query": {
"range": {
"age": {
"gte": 40
}
}
},
"aggs": {
"aggAge": {
"terms": {
"field": "age"
}
}
},
"size": 0
}
查询结果如下
2.4.3 根据age分组聚合,再对聚合后的结果按照age求平均值
powershell
GET test_query/_search
{
"aggs": {
"ageAgg": {
"terms": {
"field": "age"
},
"aggs": {
"avgAgg": {
"avg": {
"field": "age"
}
}
}
}
},
"size": 0
}
查询结果如下
2.4.4 获取结果集中的前N个数据
powershell
GET test_query/_search
{
"aggs": {
"top3": {
"top_hits": {
"size": 3
}
}
},
"size": 0
}
查询结果如下
2.4.5 获取结果集中按照age字段排序后求取前N个数据
powershell
GET test_query/_search
{
"aggs": {
"top3": {
"top_hits": {
"sort": [
{
"age" : {
"order":"desc"
}
}
],
"size": 3
}
}
},
"size": 0
}
2.5 索引模板
我们之前对索引进行一些配置信息设置,但是都是在单个索引上进行设置。在实际开发中,我们可能需要创建不止一个索引,但是每个索引或多或少都有一些共性。
比如我们在设计关系型数据库时,一般都会为每个表结构设计一些常用的字段,比如:创建时间 ,更新时间 ,备注信息 等。elasticsearch
在创建索引的时候,就引入了模板的概念,你可以先设置一些通用的模板,在创建索引的时候,elasticsearch会先根据你创建的模板对索引进行设置。
elasticsearch中提供了很多的默认设置模板,这就是为什么我们在新建文档的时候,可以为你自动设置一些信息, 做一些字段转换等。
2.5.1 创建/修改 索引
索引可使用预定义的模板进行创建这个模板称作Indextemplates.模板设置包括settings
和mappings
powershell
PUT _template/mytemplate
{
"index_patterns": [
"my*" // 该模板自动适用于索引名称以 my 开头的索引
],
// 设置模板规则
"settings": {
"index": {
"number_of_shards": "2" // 分片数量
}
},
// 影射规则
"mappings": {
"properties": {
// 字段 now 的类型及格式
"now": {
"type": "date",
"format": "yyyy/MM/dd"
}
}
}
}
可以多长操作!!
2.5.2 查看模板
powershell
GET _template/模板名称
2.5.3 更新模板
与创建命令相同,只要创建的模板名称已存在,就是更新操作,新规则覆盖旧规则
如果创建的是索引,不是索引模板,当要创建的索引已存在时,操作是不会成功的,会出错,提示索引已存在
2.5.4 应用模板
只要新创建的 索引 符合 索引模板 的匹配规则,就会自动应用模板
如:新创建 my_index_template 索引,以 my 开头,符合匹配规则
powershell
// 应用索引模板;创建以 my 开头的索引
PUT my_index_template
// 查询创建的索引
GET my_index_template
2.5.5 删除模板
powershell
DELETE _template/索引模板名称
删除后查询;结果为空;查询不存在的索引模板时,结果都为空
2.6 中文分词
我们在使用Elasticsearch官方默认的分词插件时会发现,其对中文的分词效果不佳,经常分词后得效果不是我们想要得。
2.6.1 分词操作
powershell
GET _analyze
{
"analyzer": "standard",
"text": ["zhang san"]
}
2.6.2 分词操作(不带插件情况下,中文拆分逻辑太适合)
powershell
GET _analyze
{
"analyzer": "chinese",
"text": ["我是一个三好学生"]
}
2.6.3 集成了IK插件后提供的分词
一定注意!版本下载的正确性!!!
别忘了重新启动!!
2.6.3.1 ik_smart------最少切分
powershell
GET _analyze
{
"analyzer": "ik_smart",
"text": ["我是一个三好学生"]
}
2.6.3.2 ik_max_word------最细粒度切分
相较于上者,分得更加精细
powershell
GET _analyze
{
"analyzer": "ik_max_word",
"text": ["我是一个三好学生"]
}
2.6.4 自定义分词效果
重新启动ES!!!
2.7 文档评分机制(转载)
powershell
PUT test_score
PUT test_score/_doc/1001
{
"text": "zhang kai shou bi, yin jie tai yang"
}
PUT test_score/_doc/1002
{
"text": "zhang san"
}
GET test_score/_search?explain=true
{
"query": {
"match": {
"text": "zhang"
}
}
}
- 该章节转载了 ElasticSearch之score打分机制原理
Elasticsearch
的得分机制是一个基于词频和逆文档词频的公式,简称为 TF-IDF
公式,所以先来研究下 TF-IDF
原理。
2.7.1 TF-IDF 原理
- 英文全称:
Term Frequency - Inverse Document Frequency
- 中文名称:词频-逆文档频率
常用于文本挖掘,资讯检索等应用,在NLP
以及推荐等领域都是一个常用的指标,用于衡量字词的重要性。
比较直观的解释是,如果一个词本来出现的频率就很高,如the,那么它就几乎无法带给读者一些明确的信息。
一般地,以TF-IDF
衡量字词重要性时
- 某个字词在某个文档中出现的频率越高,那么该字词对该文档就有越大的重要性,它可能会是文章的关键词(词在单个文档中出现的频率,相对于当个文档!!!)
- 但若字词在词库中出现的频率越高,那么字词的重要性越低,如
the
。(相对于整个文档集合,也就是词库)
2.7.1.1 计算公式
TF-IDF
即是两者相乘,词频乘以逆文档频率,如下:
TF-IDF
= T F ∗ I D F =TF*IDF =TF∗IDF
下标i
,j
的含义:编号为j
的文档中的词语i
在该文档中的词频,即所占比例,n
为该词语的数量。如下:
换言之,就是词语出现的次数与文档中所有词总数的比值。
T F i j = n i j n ∗ j TF_{ij} = \frac{n_{ij}}{n_{*j}} TFij=n∗jnij
N
表示文档总数,Ni
表示文档集中包含了词语 i i i 的文档数。
对分子分母加一是为了避免某些词语没有在文档中出现过,导致分母为零的情况。
IDF
针对某个词计算了它的逆文档频率,即包含该词语的文档比例的倒数(再取对数),若IDF
值越小,分母越大,说明这个词语在文档集中比较常见不具有鲜明的信息代表性,TF-IDF
的值就小。
总之TF-IDF
的值,通常希望它越大越好,大值代表性强。如下:
I D F i = l o g ( N + 1 N i + 1 ) IDF_i=log (\frac{N+1}{N_i+1}) IDFi=log(Ni+1N+1)
2.7.1.2 示例说明
有两个文档,即doc1
、doc2
,并去它们的并集
py
doc1 = "The cat sat on my bed"
doc2 = "The dog sat on my knees"
# 构建词库,union是并集操作
wordSet = set(doc1.split()).union(set(doc2.split()))
两个文档的并集如下:
{'The','bed','cat','dog','knees','my','on','sat'}
doc1
、doc2
两个文档对应的词在并集中的统计情况:
序号 | cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
2.7.1.3 计算TF
计算词频 TF
,对单个文档统计:
再理解一下,何为TF,表示单个单词占当前文档所有单词集合的比值。即1/6=0.16666666666...
cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
0.166666... | 0.166666... | 0.166666... | 0.166666... | 0 | 0.166666... | 0.166666... | 0 |
2.7.1.4 计算IDF
逆文档频率IDF
,全局只有一份逆文档频率,对所有文档统计
N
表示文档总数,
Ni`表示文档集中包含了词语i的文档数。此时N=2,共有两个文档。Ni表示含有单词的文档个数。
cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|
0.17609125... | 0.0 | 0.0 | 0.0... | 0.17609125... | 0.17609125... | 0.0 | 0.17609125... |
2.7.1.5 TF-IDF计算
最终计算:TF-IDF = TF * IDF
序号 | cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|---|
0 | 0.029349 | 0 | 0 | 0 | 0.029349 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0.029349 | 0 | 0 | 0 | 0.029349 |
2.7.2 Elasticsearch打分机制
上面介绍了TF-IDF的原理,而ES的得分机制就是基于词频和逆文档词频的公式,即TF-IDF
公式。
s c o r e ( q , d ) = c o o r d ( q , d ) ⋅ q u e r y N o r m ( q ) ⋅ ∑ t i n q ( t f ( t i n d ) ⋅ i d f ( t ) 2 ⋅ t . g e t B o o s t ( ) ⋅ n o r m ( t , d ) ) score(q,d) = coord(q,d)\cdot queryNorm(q)\cdot \sum_{t in q}(tf(t in d)\cdot idf(t){^2}\cdot t.getBoost()\cdot norm(t,d)) score(q,d)=coord(q,d)⋅queryNorm(q)⋅tinq∑(tf(tind)⋅idf(t)2⋅t.getBoost()⋅norm(t,d))
公式中将查询作为输入,使用不同的手段来确定每一篇文档的得分,将每一个因素最后通过公式综合起来,返回该文档的最终得分。这个综合考量的过程,在ES中这种相关性称为得分。
考虑到查询内容和文档的关系比较复杂,所以公式中需要输入的参数和条件非常得多,但是其中比较重要的其实是TF-IDF
算法 ,再次解释一下。
TF
(词频)
Term Frequency : 搜索文本中的各个词条在查询文本中出现了多少次,次数越多,就越相关,得分会比较高
IDF
(逆文档频率)
Inverse Document Frequency : 搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,说明越不重要,也就越不相关,得分就比较低。
2.7.2.1 示例说明
在查询语句的最后加上explain=true
,会把得分过程打印。
注:当前
ElasticSearch
的scorpios
索引里,只有一个文档。
powershell
PUT itwluo
PUT itwluo/_doc/1001
{
"text": "java"
}
GET itwluo/_search
{
"query": {
"match": {
"text": "java"
}
}
}
result
json
{
"took": 992,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "itwluo",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"text": "java"
}
}
]
}
}
详细结果
json
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_shard": "[itwluo][0]",
"_node": "EX7ZCQpSRLu-OWEZjQazog",
"_index": "itwluo",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"text": "java"
},
"_explanation": {
"value": 0.2876821,
"description": "weight(text:java in 0) [PerFieldSimilarity], result of:",
"details": [
{
"value": 0.2876821,
"description": "score(freq=1.0), computed as boost * idf * tf from:",
"details": [
{
"value": 2.2,
"description": "boost",
"details": []
},
{
"value": 0.2876821,
"description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
"details": [
{
"value": 1,
"description": "n, number of documents containing term",
"details": []
},
{
"value": 1,
"description": "N, total number of documents with field",
"details": []
}
]
},
{
"value": 0.45454544,
"description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
"details": [
{
"value": 1,
"description": "freq, occurrences of term within document",
"details": []
},
{
"value": 1.2,
"description": "k1, term saturation parameter",
"details": []
},
{
"value": 0.75,
"description": "b, length normalization parameter",
"details": []
},
{
"value": 1,
"description": "dl, length of field",
"details": []
},
{
"value": 1,
"description": "avgdl, average length of field",
"details": []
}
]
}
]
}
]
}
}
]
}
}
新增数据后,观察分值变化
powershell
PUT itwluo/_doc/1002
{
"text": "java bigdata"
}
#查询文档数据
GET itwluo/_search?explain=true
{
"query": {
"match": {
"text": "java"
}
}
}
详细结果
json
{
"took": 609,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.21110919,
"hits": [
{
"_shard": "[itwluo][0]",
"_node": "EX7ZCQpSRLu-OWEZjQazog",
"_index": "itwluo",
"_id": "1001",
"_score": 0.21110919,
"_source": {
"text": "java"
},
"_explanation": {
"value": 0.21110919,
"description": "weight(text:java in 0) [PerFieldSimilarity], result of:",
"details": [
{
"value": 0.21110919,
"description": "score(freq=1.0), computed as boost * idf * tf from:",
"details": [
{
"value": 2.2,
"description": "boost",
"details": []
},
{
"value": 0.18232156,
"description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
"details": [
{
"value": 2,
"description": "n, number of documents containing term",
"details": []
},
{
"value": 2,
"description": "N, total number of documents with field",
"details": []
}
]
},
{
"value": 0.5263158,
"description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
"details": [
{
"value": 1,
"description": "freq, occurrences of term within document",
"details": []
},
{
"value": 1.2,
"description": "k1, term saturation parameter",
"details": []
},
{
"value": 0.75,
"description": "b, length normalization parameter",
"details": []
},
{
"value": 1,
"description": "dl, length of field",
"details": []
},
{
"value": 1.5,
"description": "avgdl, average length of field",
"details": []
}
]
}
]
}
]
}
},
{
"_shard": "[itwluo][0]",
"_node": "EX7ZCQpSRLu-OWEZjQazog",
"_index": "itwluo",
"_id": "1002",
"_score": 0.160443,
"_source": {
"text": "java bigdata"
},
"_explanation": {
"value": 0.160443,
"description": "weight(text:java in 0) [PerFieldSimilarity], result of:",
"details": [
{
"value": 0.160443,
"description": "score(freq=1.0), computed as boost * idf * tf from:",
"details": [
{
"value": 2.2,
"description": "boost",
"details": []
},
{
"value": 0.18232156,
"description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
"details": [
{
"value": 2,
"description": "n, number of documents containing term",
"details": []
},
{
"value": 2,
"description": "N, total number of documents with field",
"details": []
}
]
},
{
"value": 0.40000004,
"description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
"details": [
{
"value": 1,
"description": "freq, occurrences of term within document",
"details": []
},
{
"value": 1.2,
"description": "k1, term saturation parameter",
"details": []
},
{
"value": 0.75,
"description": "b, length normalization parameter",
"details": []
},
{
"value": 2,
"description": "dl, length of field",
"details": []
},
{
"value": 1.5,
"description": "avgdl, average length of field",
"details": []
}
]
}
]
}
]
}
}
]
}
}
2.7.2.2 计算 TF 值
T F = f r e q / ( f r e q + k 1 ∗ ( 1 − b + b ∗ d l / a v g d l ) ) TF = freq/(freq + k1 * (1-b+b*dl/avgdl)) TF=freq/(freq+k1∗(1−b+b∗dl/avgdl))
参数 | 含义 | 取值 |
---|---|---|
freq | 文档中出现词条的次数 | 1.0 |
k1 | 术语饱和参数 | 1.2(默认值) |
b | 长度规格参数(单词长度对于整个文档的影响程度) | 0.75(默认值) |
dl | 当前文中分解的字段长度 | 1.0 |
avgdl | 查询文档中分解字段数量/查询文档数量 | 1.0 |
TF(词频) | 1.0/(1+1.2 * (1-0.75+0.75 * 1.0/1.0)) | 0.454545 |
2.7.2.3 计算 IDF 值
I D F = l n ( 1 + ( N − n + 0.5 ) / ( n + 0.5 ) ) IDF = ln(1+(N−n+0.5)/(n+0.5)) IDF=ln(1+(N−n+0.5)/(n+0.5))
参数 | 含义 | 取值 |
---|---|---|
N | 包含查询字段的文档总数(不一定包含查询词条) | 1 |
n | 包含查询词条的文档数 | 1 |
IDF(逆文档频率) | log(1+(1-1+0.5)/(1+0.5)) | 0.2875821 |
注:这里的 ln是底数为e 的对数
2.7.2.4 计算文档得分
s c o r e = t f b o o s t ∗ i d f ∗ t f score = tf boost∗idf∗tf score=tfboost∗idf∗tf
参数 | 含义 | 取值 |
---|---|---|
boost | 词条权重 | 2.2(基础值)*查询权重(1) |
idf | 逆文档频率 | 0.2876821 |
tf | 词频 | 0.454545 |
score(得分) | 2.20.28768210.454545 | 0.2876821 |
2.7.2.5 增加新的文档测试得分
- 增加一个毫无关系的文档
yaml
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "spark"
}
# 得分:0.6931741
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档无词条相关信息,所以匹配的文档数据得分就应该较高
- 增加一个一模一样的文档
yaml
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "hello"
}
# 得分:0.18232156
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档含词条相关信息,且多个文件含有词条,所以显得不是很重要,得分会变低
- 增加一个含有词条,但是内容较多的文档
yaml
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "hello elasticsearch"
}
# 得分:0.14874382
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档含词条相关信息,但只是其中一部分,所以查询文档的分数会变得更低一些。
2.7.3 案列
2.7.3.1 需求
查询文档标题中含有Hadoop
,Elasticsearch
,Spark
的内容,优先选择Spark
的内容
2.7.3.2 准备数据
yaml
# 创建索引
PUT /test
# 准备数据
PUT /test/_doc/1001
{
"title" : "Hadoop is a Framework",
"content" : "Hadoop 是一个大数据基础框架"
}
PUT /test/_doc/1002
{
"title" : "Hive is a SQL Tools",
"content" : "Hive 是一个 SQL 工具"
}
PUT /test/_doc/1003
{
"title" : "Spark is a Framework",
"content" : "Spark 是一个分布式计算引擎"
}
2.7.3.3 查询数据
yaml
# 查询文档标题中含有"Hadoop","Elasticsearch","Spark"的内容
GET /test/_search?explain=true
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "Hadoop", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Hive", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Spark", "boost": 1
}
}
}
]
}
}
}
此时会发现,Spark
的结果并不会放置在最前面
此时可以更改 Spark
查询的权重参数 boost
,看看查询的结果有什么不同
yaml
# 查询文档标题中含有"Hadoop","Elasticsearch","Spark"的内容
GET /test/_search?explain=true
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "Hadoop", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Hive", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Spark", "boost": 2
}
}
}
]
}
}
}