索引排序

edit

在Elasticsearch中创建新索引时,可以配置每个分片内的段如何排序。默认情况下,Lucene不应用任何排序。index.sort.*设置定义了应使用哪些字段对每个段内的文档进行排序。

允许对包含嵌套对象的映射应用索引排序,只要index.sort.*设置中不包含嵌套字段。

例如,以下示例展示了如何在一个字段上定义排序:

PUT my-index-000001
{
  "settings": {
    "index": {
      "sort.field": "date", 
      "sort.order": "desc"  
    }
  },
  "mappings": {
    "properties": {
      "date": {
        "type": "date"
      }
    }
  }
}

此索引按 date 字段排序

…​ 按降序排列。

也可以通过多个字段对索引进行排序:

PUT my-index-000001
{
  "settings": {
    "index": {
      "sort.field": [ "username", "date" ], 
      "sort.order": [ "asc", "desc" ]       
    }
  },
  "mappings": {
    "properties": {
      "username": {
        "type": "keyword",
        "doc_values": true
      },
      "date": {
        "type": "date"
      }
    }
  }
}

此索引首先按 username 排序,然后按 date 排序

…​ 按 username 字段升序排列,按 date 字段降序排列。

索引排序支持以下设置:

index.sort.field
用于对索引进行排序的字段列表。 仅允许使用具有doc_valuesbooleannumericdatekeyword字段。
index.sort.order

每个字段要使用的排序顺序。 order 选项可以具有以下值:

  • asc: 升序
  • desc: 降序。
index.sort.mode

Elasticsearch 支持对多值字段进行排序。 mode 选项控制选择哪个值来对文档进行排序。 mode 选项可以具有以下值:

  • min: 选择最小值。
  • max: 选择最大值。
index.sort.missing

missing 参数指定如何处理缺少该字段的文档。 missing 值可以具有以下值:

  • _last: 没有该字段值的文档将排在最后。
  • _first: 没有该字段值的文档将排在最前。

索引排序只能在索引创建时定义一次。不允许在现有索引上添加或更新排序。索引排序还会在索引吞吐量方面产生成本,因为文档必须在刷新和合并时进行排序。在激活此功能之前,您应该测试其对应用程序的影响。

搜索请求的提前终止

edit

默认情况下,Elasticsearch 中的搜索请求必须访问与查询匹配的每个文档,以检索按指定排序排序的顶部文档。 尽管当索引排序和搜索排序相同时,可以限制每个分段应访问的文档数量,以检索全局排名前 N 的文档。 例如,假设我们有一个按时间戳字段排序的事件索引:

PUT events
{
  "settings": {
    "index": {
      "sort.field": "timestamp",
      "sort.order": "desc" 
    }
  },
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date"
      }
    }
  }
}

此索引按时间戳降序排列(最新在前)

您可以搜索最近的10个事件,使用:

GET /events/_search
{
  "size": 10,
  "sort": [
    { "timestamp": "desc" }
  ]
}

Elasticsearch 会检测到每个分段的顶部文档已经在索引中排序,并且只会比较每个分段的第一个 N 个文档。 与查询匹配的其余文档会被收集起来以计算结果的总数,并构建聚合。

如果你只寻找最近的10个事件,并且对匹配查询的文档总数不感兴趣,你可以将track_total_hits设置为false:

GET /events/_search
{
  "size": 10,
  "sort": [ 
      { "timestamp": "desc" }
  ],
  "track_total_hits": false
}

将使用索引排序来对顶级文档进行排名,并且每个段落在找到前10个匹配项后将提前终止收集。

这次,Elasticsearch不会尝试计算文档的数量,并且一旦每个分段收集到N个文档,就能够终止查询。

{
  "_shards": ...
   "hits" : {  
      "max_score" : null,
      "hits" : []
  },
  "took": 20,
  "timed_out": false
}

由于提前终止,匹配查询的总点击数未知。

聚合将收集所有匹配查询的文档,无论track_total_hits的值如何

使用索引排序来加速连接

edit

索引排序可以用于组织Lucene文档ID(不要与_id混淆),以便使合取(a AND b AND …​)更高效。为了提高效率,合取依赖于这样一个事实:如果任何子句不匹配,那么整个合取就不匹配。通过使用索引排序,我们可以将不匹配的文档放在一起,这将有助于高效地跳过不匹配合取的大范围文档ID。

这个技巧只适用于低基数字段。一个经验法则是,你应该首先对那些既具有低基数又经常用于过滤的字段进行排序。排序顺序(ascdesc)并不重要,因为我们只关心将匹配相同子句的值放在一起。

例如,如果您正在为待售汽车建立索引,按燃油类型、车身类型、品牌、注册年份和最后按里程数排序可能会很有趣。