es的排序默认按照分数进行排序,也可以指定具体的排序字段进行排序
排序的语法:
#可以设置单字段也可以多字段进行排序
GET demo/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"name": {
"order": "desc"
}
}
]
}
默认text类型的属性是不能进行排序的,否则会报错,如果要进行排序需要在mapping设定该字段fielddata属性为true。
#ES默认fielddata的值为false
PUT demo/_mapping
{
"properties" : {
"content" : {
"type" : "text",
"fielddata":true
},
"name" : {
"type" : "keyword"
}
}
}
排序是针对原始字段内容进行的,所以无法使用倒排索引,而是使用正排索引,通过文档的id和字段快速得到字段的原视内容。ES有两种实现方式:Fielddata 和 Doc Values(列式存储,对text类型无效)
Doc Values | Field data | |
---|---|---|
何时创建 | 索引时,和倒排索引同时创建 | 搜索时动态创建 |
创建位置 | 磁盘文件 | jvm heap |
优点 | 避免大量内存占用 | 索引速度快,不用占用额外的磁盘空间 |
缺点 | 降低索引速度,占用额外磁盘空间 | 文档过多时,动态创建开销大,占用过多jvm heap |
缺省值 | ES2.x后 | ES1.x及以前 |
所以一般建议不会对全文本进行排序。
Doc Values默认是开启的,当明确不需要进行排序或者聚合分析时可以设置关闭(可以增加索引速度,降低磁盘使用空间),但是开启时需要重建索引。**
PUT demo
{
"mappings": {
"properties": {
"content":{
"type": "text"
},
"name":{
"type": "keyword",
"doc_values": false
}
}
}
}
—————————————————————————————————————————————————-
分页和遍历
ES的分页可以通过From和size参数进行,但是有一个问题就是当分页数过深的时候,会造成性能开销过大。这是由于当一个查询:From=990,size=10的时候
会首先在每个分页获取前1000个文档,然后通过coordinating Node聚合所有结果,再通过排序选取前1000个文档,返回其中的10个数据;所以页数越深,占用的内存越大;而ES为了避免此种情况,设定了限定10000个文档,超过了此阈值,就会报错。
为了避免深度分页的解决办法:
1、Search_After的API
#如下面的例子,首先需要指定排序的字段(可以多个),然后在search_after中指定起始位置的值,
#那么ES将从该位置进行查询往下的内容
GET demo/_search
{
"size": 1,
"query": {
"match_all": {}
},
"search_after":[
"张三"
]
,"sort": [
{"name": { "order": "desc" }}
]
}
缺点:不支持指定页数,只能往下翻,需要记录上一次查询的最后一个值(张三)
**
2、Scroll API
创建一个快照,有新的数据写入以后,在当前快照无法被查询
每次查询需要输入上一次的Scroll ID
一般用于全部导出数据
##第一步:创建快照
GET demo/_search?scroll=5m
{
"size": 1,
"query": {
"match_all": {}
}
}
#第二步:根据scroll_id进行查询
GET /_search/scroll
{
"scroll":"1m",
"scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFHUxOU05M1lCV2xELTdZZmpfdVQ1AAAAAAAAA0wWNjJESmFhZVhUQmVOOTlDaEtBTXgtUQ=="
}