目录
1、Es基本定义
1.1 文档(Document)
1.2 索引(Index)
1.3 类型(Type)
在 7.0 之前,每一个索引是可以设置多个 Types 的,每个 Type 会拥有相同结构的文档,但是在 6.0 开始,Type 已经被废除,在 7.0 开始,一个索引只能创建一个 Type,也就是 _doc。每个索引里都可以有一个或多个 Type,Type 是索引中的一个逻辑数据分类,一个 Type 下的文档,都有相同的字段
为什么要取消type?
同一个Index下的不同实体(不同type意味着field往往不一样,可称为不同实体)太多,且分布稀疏不均,严重干扰了Lucene压缩文档的能力,所以在彻底抛弃type之后,ES的存储能力将会有所提高。
所以ES给type制定了消亡路线:
type在6.x中只能有一个,可自定义。
type在7.x中只能有一个,且只能是_doc。
type在8.x(未来版本)彻底取消,API会大变,以前的<INDEX>/<TYPE>/<DOC>的方式会变成<INDEX>/<DOC>
1.4 映射(Mapping)
每个索引都可以对字段做类型的定义,这个过程就是映射。映射就相当于数据库中我们去定义字段的类型。
映射包括了该类型的文档中可能出现的所有字段,并告诉Es如果索引一个文档内的多个字段。

1.5 集群(Cluster)
1.6 节点(Node)
节点其实就是一个 ES 实例,本质上是一个 Java 进程,一台机器上可以运行多个 ES 进程,但是生产环境一般建议一台机器上只运行一个 ES 实例。
每一个节点都有自己的名字,节点名称很重要(在执行运维管理操作的时候),可以通过配置文件进行配置,或者启动的时候 -E node.name=node1 指定。每一个节点在启动之后,会分配一个 UID,保存在 data 目录下。
1.7 分片(Shard)
分片分为两类,一类为主分片(Primary Shard),另一类为副本分片(Replica Shard)。
主分片主要用以解决水平扩展的问题,通过主分片,就可以将数据分布到集群上的所有节点上,一个主分片就是一个运行的 Lucene 实例,当我们在创建 ES 索引的时候,可以指定分片数,但是主分片数在索引创建时指定,后续不允许修改,除非使用 Reindex 进行修改。
副本分片用以解决数据高可用的问题,也就是说集群中有节点出现硬件故障的时候,通过副本的方式,也可以保证数据不会产生真正的丢失,因为副本分片是主分片的拷贝,在索引中副本分片数可以动态调整,通过增加副本数,可以在一定程度上提高服务查询的性能(读取的吞吐)。

1.8 分段
elasticsearch 中每个索引都会创建一个到多个分片和零个到多个副本,这些分片或副本实质上都是lucene索引。
lucene索引是基于多个索引段创建,索引文件中绝大部分数据都是只写一次,读多次,而只有用于保存文档删除信息的文件才会被多次更改
2、索引
2.1 索引新数据
当一个创建新索引的请求被打到Es集群中的某个节点后,该节点首先选择文档要被索引到哪个分片。默认情况下,文档会在分片中均匀的分布:对于每片文档,分片是通过文档的Id字符串进行计算决定的。如果没有指定id,则会自动生成id,并hash后到指定分片存储。
分片确定后,接收请求的节点将文档转发到该分片所在的节点,并将数据写入到该分片,以及该分片的副本。等所有分片和副本分片完成后,会返回成功。

2.2 搜索数据
搜索的时候,接受请求的节点将请求转发到一组包含所有数据的分片。Es使用轮询机制选择可用的分片,并将搜索转发过去
怎么决定哪个分片:
- 搜索条件有id:任意连上一个Es节点,然后根据hash这个id找到对应的分片,该分片可能是主分片也可能是副本分片。
- 全文检索:任意连上一个Es节点,然后向所有的分片发起关键字查询,其他节点把数据返回到当前节点并进行汇总

2.4 过滤器
过滤器和查询类似,但是它们在评分机制和搜索行为的性能上,有所不同。
查询会为特定的词条进行计算得分,搜索的过滤器只是会返回 文档是否匹配过滤条件,不会评分,只是简单的是与否。

由于这个差异,过滤器比普通查询更快,而且还可以被缓存。

3 分析数据
3.1 发生时机
分析过程是文档被发到Es节点后,节点在创建倒排索引之前会先对数据进行分析。对哪个字段进行分析是可以进行定制对,在进行索引mapping设置时,可以指定字段是否需要进行分析。
3.2 过程
标准分析步骤如下:
- 字符过滤:使用字符过滤器转变字符
- 文本切分分词:将文本切分为单个或多个分词
- 分词过滤:使用分词过滤器转变每个分词

3.3 用Api分析文本数据
3.3.1 analyze Api
- 对指定字符串使用指定分析器进行分析,直接展示分析结果
- 可以分别指定字符过滤器、分词器、分词过滤器
- Testing analyzers | Elasticsearch Guide [6.8] | Elastic
下面我是用的自己安装的一个ik分词器插件进行的分析


3.3.2 term Vectors api
- 查看某个具体文档的具体索引信息
- 这个文档有哪些分词,每个分词出现的位置,频率等
- Term Vectors | Elasticsearch Guide [6.8] | Elastic
设置term_statistics=true 后将返回:
total term frequency, 一个term在所有document中出现的频率;
document frequency,有多少document包含这个term
设置field_statistics=true 后将返回:
document count: 有多少document包含这个field;
sum of document frequency:一个field中所有term的df之和;
sum of total term frequency:一个field中的所有term的tf之和

3.4 内置的分析器

4 相关性运算
做搜索查询,除了要考虑我的搜索条件能匹配到哪些文档,还要考虑文档的相关性匹配。
相关性就是对于某个查询而言,文档A比文档B匹配度更高,更精确。
在Es中确定文档和查询有多么相关的过程被称为打分(scoring)。
4.1 如何打分
4.1.1 词频(TF)
考虑给一篇文档打分的首要方式,是查看一个词条在文本中出现的次数。
例:
"我们都是中国人"
"中国人爱中国人"
上面的 "中国人" 在两个句子都出现了,第一句出现了1次,第二句出现了2次。所以第一句 词频是1,第二句词频是2,第二句得分更高
4.1.2 逆文档频率(IDF)
比文档词频稍微复杂一点的是逆文档。如果一个分词在索引的不同文档中出现越多的次数,那么它就越不重要。
1和2 结合起来可以称为TF-IDF 评分方法。
4.1.3 Okapi BM25
BM25是Lucene中第二流行的评分方法,仅次于TF-IDF。它是概率性的相关性算法,这意味着分数可以认为是给文档和查询匹配的概率。
相关评分算法参考: https://segmentfault.com/a/1190000019630099?utm_source=tag-newest
4.2 boosting
- boosting是一个可以用来修改文档的相关性的设置。
- boosting有两种设置方式,1、可以在建立时,在mapping下的字段设置处设置
2、在查询时
推荐在查询时进行动态的设置,这样更灵活,允许随时更改。
4.2.1 boost如何计算
boost的数值并不是精确的乘数。在计算分数的时候boost数值是被标准计算的。
例如:如果为每个字段指定了10的boost,那么最终计算后每个字段会获得1的值。
设置的时候应该考虑的是相对的值,比如 单独将某一个字段的boost设置为3,那么这个字段的重要性就是比其他字段大 3倍
4.2.2 mapping时设置boosting

4.2.3 查询时设置boost
下面是给所有字段设置了 3

4.3 function_score
function_score查询允许用户指定任何数量的任意函数,让他们作用于匹配了初识查询的文档,修改得分,达到精细化控制结果相关性的目的。
function_score 查询 | Elasticsearch: 权威指南 | Elastic
4.3.1 weight函数
weight是最简单的function函数,它将得分乘以一个常数。之前提到的boost字段是按照对比其他字段的标准来打分。weight是会真正的乘以确定的数值。
不用weight函数

使用functions weight函数:

4.3.2 field_value_factor
有时候我们希望使用文档中的某些数据来增加分数。field_value_factor函数将包含数值的字段的名称作为输入,选择性的将其值乘以常数,然后最终对其运用数学函数。
直接查询:


4.5 字段数据(FieldData)
当你希望查询一个词条并获取匹配的文档时,目前我们应用的都是倒排索引。但是当需要在某个字段上进行排序或者用一些字段做聚集时,Es需要知道你的排序或者聚集字段在文档中的确切值。
- 字段数据缓存就是将字段数据加载到缓存里,这是进行快速排序或者聚集的实现方式,但是由此也会带来一个问题,当文档太多时,会消耗大量的内存。
- DocValues不支持索引(anaylyzed)字段,FieldData支持text类型字段。FieldData默认不开启,想要开启,需要在映射时配置开启
- FieldData会很消耗jvm的内存,容易造成OOM。所以设计时应该用 text索引字段用于全文检索,其他字段使用DocValues方式进行排序,聚合。
5 聚集
聚集可以理解为分类统计,比如 对一组文档的某个词条进行计数,或者计算某个数值型字段的平均值
5.1 度量聚集
5.1.1 统计数据
简单统计,包括 avg,max,min,sum 等只会输出一个结果


5.2 多桶型聚集
Bucket可以理解为一个桶,它会遍历文字中的内容,凡事符合某一要求的就放在一个桶中,分桶相当于sql中的group by。
5.2.1 terms聚集
根据某一项的每个唯一的值来聚合
- Es为了拿到排序后前n个词条,会必须从每个分片获取一定数量的词条(可以通过参数shard_size设置)并且将结果聚集
这种机制意味着对于某些未能在单个分片上排名靠前的词条,可能会得到不正确的技术,可以通过shard_size调整,但是这样带来的结果 就是可能实现聚集操作会比较耗时间和资源。

5.2.2 range聚集
就是范围的聚集
"aggs": {
"prices_range": {
"range": {
"field": "price",
"ranges": [
{
"key": "<50000",
"to":50000
},
{
"key": "50000~80000",
"from": 50000,
"to": 80000
},
{
"key": ">80000",
"from": 80000
}
]
}
}
}5.2.3 histogram聚集
为了处理数值型的范围,还可以使用histogram聚集。这个聚集和range聚集很像,range聚集是需要定义一个个的范围。而histogram是定义一个固定的间距,Es会根据字段的所有值为你自动构建多个范围。
5.2.3.1 普通 histogram聚集
{
"aggs": {
"num_histogram": {
"histogram": {
"field": "num",
"interval": 2
}
}
}
}5.2.3.1 Date Histogram
这个是针对时间格式数据的直方图聚合
{
"aggs": {
"sales_over_time": {
"date_histogram": {
"field": "sellTime",
"interval": "month",
"format": "yyyy-MM-dd"
}
}
}
}
参考:
Elasticsearch实战
各种网络博文