一、问题描述
问题概要:ES数据不变,但每次刷新页面返回的数据排序不一致
详细描述:协议物品按照modifiedTime排序,当物品在同一个协议时,这个协议下的所有物品的更新时间都是相同的,所以modifiedTime相同的协议物品在每次请求时,返回的顺序可能不一致
原因:ES震荡问题
Bouncing Results
想象一下有两个文档有同样值的时间戳字段,搜索结果用timestamp字段来排序。 由于搜索请求是在所有有效的分片副本间轮询的,那就有可能发生主分片处理请求时,这两个文档是一种顺序, 而副本分片处理请求时又是另一种顺序。
这就是所谓的bouncing results问题: 每次用户刷新页面,搜索结果表现是不同的顺序。 让同一个用户始终使用同一个分片,这样可以避免这种问题, 可以设置preference参数为一个特定的任意值比如用户会话ID来解决。
解决方案:
1. preference(推荐)
![](https://img.haomeiwen.com/i13860086/f77d25cd63e00f3d.png)
先用modifiedTime排序,再用_uid排序
2. es 唯一主键排序(临时方案)
![](https://img.haomeiwen.com/i13860086/dc016ff9610b5de4.png)
当业务上需要按照协议中物品的排版顺序进行排序时,这种更为合适(下面会介绍更好的官方推荐方案 来替代此方案),
二、preference
三、_uid
1. 元数据
文档标识与四个元数据字段相关:
_id 文档的 ID 字符串
_type 文档的类型名
_index 文档所在的索引
_uid _type 和 _id 连接在一起构造成 type#id
默认情况下,_uid字段是被存储(可取回)和索引(可搜索)的。_type字段被索引但是没有存储,_id和_index字段则既没有被索引也没有被存储,这意味着它们并不是真实存在的。
尽管如此,你仍然可以像真实字段一样查询_id字段。Elasticsearch 使用_uid字段来派生出_id。 虽然你可以修改这些字段的index和store设置,但是基本上不需要这么做。
The value of the _id field is accessible in certain queries (term, terms, match, query_string,simple_query_string), but not in aggregations, scripts or when sorting, where the _uid field should be used instead
所以,如果想用全局唯一的docId进行排序,需要使用_uid,而不是_id
2. 新版本变化
Deprecated in 6.0.0.
Now that types have been removed, documents are uniquely identified by their_id and the_uidfield has only been kept as a view over the_idfield for backward compatibility.
由于公司当前用的ElasticSearch版本的是5.1.1,当前版本只能使用_uid来排序;在6.x及以上版本可以使用_id来排序,聚合,查询,详见:https://www.elastic.co/guide/en/elasticsearch/reference/master/mapping-id-field.html
官方建议
The value of the _id field is also accessible in aggregations or for sorting, but doing so is discouraged as it requires to load a lot of data in memory. In case sorting or aggregating on the _idfield is required, it is advised to duplicate the content of the _id field in another field that has doc_values enabled.
尽管ES 6.x及以上可以直接使用_id来进行排序,但是官方推荐使用一个重复的字段存储_id的值,并且让doc_value设置为enabled(默认设置)
因此,上述方案二最好替换为:新增一个字段,值与_id一致,并开启doc_value,以提供更好的性能,并且_uid 在更高版本中已经被删除了
扩展思考:mysql的排序是怎样的呢?
网友评论