es搜索核心与实战Day07
1.文档到分片的路由算法
- shard=hash(_rounting)%number_of_primary_shards
Hash算法确保文档均匀分散到分片中
默认的_routing 值是文档id
可以自行制定routing数值,例如用相同国家的商品,都分配到指定的shard
设置Index Setting后,Primary数,不能随意修改的更本原因
更新一个文档
2.分片及其生命周期
a.倒排索引的不可变性
- 倒排索引采用Immutable Design,一旦生成,不可更改
- 不可变性,带来了的好处如下:
1.无需考虑并发写文件的问题,避免了锁机制带来的性能问题
2.一旦读入内核的文件系统缓存,便留在哪里。只要文件系统存有足够大的空间,大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能
3.缓存容易生成和维护/数据可以被压缩
3.什么是Refresh
- 将Index buffer写入Segment的过程叫Refresh。Refresh不执行fsync操作
- Refresh频率:默认1秒发生一次,可通过index.refresh_interval配置。Refresh后,数据就可以被搜索到。这也是为什么Elasticsearch被称为近实时搜索
- 如果系统有大量的数据写入,那就会产生很多的Segment
- Index Buffer被占满时,会触发Refresh,默认值是JVM的10%
4.什么是Transaction Log
- Segment写入磁盘的过程相对耗时,借助文件系统缓存,Refresh时,先将Segment写入缓存以开放查询
- 为了保证数据不会丢失。所以在Index文档时,同时写入Transaction Log,高版本开始,Transaction Log默认落盘。每个分片有一个Transaction Log
- 在ES Refresh时,Index Buffer被清空,Transaction Log不会清空
5.什么是Flush
- ES Flush&Lucene Commit
调用Refresh,Index Buffer清空并且Refresh
调用fsync,将缓存中的Segments写入磁盘
清空(删除)Transaction Log
默认30分钟调用一次
Transaction Log满(默认512MB)
6.Merge
- Segment很多,需要被定期合并
减少Segments/删除已经删除的文档
- ES和Lucene会自动进行Merge操作
POST my_index/_forcemerge
7.剖析分布式查询及相关性算分
1.Query阶段
- 用户发出搜索请求到ES节点。节点收到请求后,会以Coordinating节点的身份在6个主妇分片中随机选择3个分片,发送查询请求
- 被选中的分片执行查询,经行排序。然后,每个分片都会返回From+Size个排序后的文档Id和排序值给Coordinating节点
2.Fetch阶段
- Coordinating Node会将Query阶段,从每个分片获取的排序后的文档Id列表,重新进行排序。选取From到From+Size个文档的Id
- 以multi get请求的方式,到相应的分片获取详细的文档数据
3.Query Then Fetch潜在的问题
- 性能问题
每个分片上需要查的文档个数=from+size
最终协调点需要处理:number_of_shard*(from+size)
深度分页
-
相关性算分
每个分片都基于自己的分片上的数据经行相关度计算。这会导致打分偏离的情况,特别是数据很少时。相关性算分之间是相互独立。当文档总数很少的情况下,如果主分片大于1,主分片数越多,相关性算分会越不准
4.解决算分不准的方法
- 数据量不大的时候,可以将主分片数设置为1
当数据量足够大时侯,只要保证文档均匀分散在各个分片上,结果一般就不会出现偏差
- 使用DFS Qurery Then Fetch
搜索的URL中指定参数“_search?search_type=dfs_query_then_fetch”
到每个分片把个分片的词频和文档频率进行搜集,然后完整的进行一次相关性算分,耗费更多的CPU和内存,执行性能低下,一般不建议使用
POST message/_doc
{
"content":"good"
}
POST message/_doc
{
"content":"good morning everyone"
}
POST message/_doc
{
"content":"good morning"
}
POST message/_search
{
"query": {
"term": {
"content": {
"value": "good"
}
}
}
}
DELETE message
PUT message
{
"settings": {
//20个分片算分一样
"number_of_shards": 20
}
}
GET message
POST message/_doc?routing=1
{
"content":"good"
}
POST message/_doc?routing=2
{
"content":"good morning"
}
POST message/_doc?routing=3
{
"content":"good morning everyone"
}
POST message/_search
{
"explain": true,
"query": {
"term": {
"content": {
"value": "good"
}
}
}
}
//type dfs_query_then_fetch
POST message/_search?search_type=dfs_query_then_fetch
{
"query": {
"term": {
"content": {
"value": "good"
}
}
}
}
8.排序及DocValues&Fielddata
1.排序
//单字段排序
POST /kibana_sample_data_ecommerce/_search
{
"size":5,
"query": {
"match_all": {
}
},
"sort": [
{
"order_date": {
"order": "desc"
}
}
]
}
//多字段排序
POST /kibana_sample_data_ecommerce/_search
{
"size":5,
"query": {
"match_all": {
}
},
"sort": [
{
"order_date": {"order":"desc"}},
{"_doc":{"order": "asc" }},
{"_score":{"order": "desc"}}
]
}
//对text排序报错
POST /kibana_sample_data_ecommerce/_search
{
"size":5,
"query": {
"match_all": {
}
},
"sort": [
{
"customer_full_name": {
"order": "desc"
}
}
]
}
//打开text的 fielddata
PUT kibana_sample_data_ecommerce/_mapping
{
"properties":{
"customer_full_name":{
"type":"text",
"fielddata":true,
"fields":{
"keyword":
{
"type":"keyword",
"ignore_above":256
}
}
}
}
}
2.排序的过程
- 排序是针对字段原始内容进行的。倒排索引无法发挥作用
- 需要用到正排索引。通过文档Id和字段快速得到字段原始内容
- Elasticseach有两种实现方法
1.Fielddata
2.Dov Values(列式存储,对Text类型无效)
关闭Dov Values
- 默认启用,可以通过Mapping设置关闭
增加索引的速度/减少磁盘空间
- 如果重新打开,需要重建索引
- 什么时候需要关闭