Elasticsearch对已排序的聚合结果进行分页

5 elasticsearch

据我所知,没有办法在Elasticsearch中执行以下操作:

SELECT * FROM myindex
GROUP BY agg_field1, agg_field2, agg_field3 // aggregation
ORDER BY order_field1, order_field2, order_field3 // sort
LIMIT 1000, 5000 // paginate -- get page 6 of size 1000 records
Run Code Online (Sandbox Code Playgroud)

以下是一些有关此问题的相关文件:

有没有办法在Elasticsearch中执行上述操作?我们的一个限制是我们永远不会有超过10M的记录,所以我们(希望)不应该遇到内存错误.我的想法是这样做:

  • 进行聚合查询
  • 从中获取结果数量
  • 根据我们想要的结果和页面大小将其拆分为N个段
  • 使用上述段重新运行查询

实现这一目标的最佳方法是什么?在您的回答/建议中,您能否发布一些有关如何在ES中完成上述SQL查询的示例代码?


作为此问题的更新,这是一个公共索引,用于测试:

# 5.6
e=Elasticsearch('https://search-testinges-fekocjpedql2f3rneuagyukvy4.us-west-1.es.amazonaws.com')
e.search('testindex')

# 6.4 (same data as above)
e = Elasticsearch('https://search-testinges6-fycj5kjd7l5uyo6npycuashch4.us-west-1.es.amazonaws.com')
e.search('testindex6')
Run Code Online (Sandbox Code Playgroud)

它有10,000条记录.随意测试:

在此输入图像描述

我正在寻找的查询如下(在sql中):

SELECT * FROM testindex
GROUP BY store_url, status, title
ORDER BY title ASC, status DESC
LIMIT 100 OFFSET 6000
Run Code Online (Sandbox Code Playgroud)

换句话说,我希望对聚合结果(具有多个聚合)进行排序并获得偏移量.

Val*_*Val 4

聚合在这里可能会有所帮助composite因为它允许您按多个字段进行分组,然后对结果进行分页。它不允许您做的唯一一件事是跳转到给定的偏移量,但如果有必要,您可以通过从客户端代码进行迭代来实现这一点。

因此,这里有一个示例查询来执行此操作:

POST testindex6/_search
{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 100,
        "sources": [
          {
            "store": {
              "terms": {
                "field": "store_url"
              }
            }
          },
          {
            "status": {
              "terms": {
                "field": "status",
                "order": "desc"
              }
            }
          },
          {
            "title": {
              "terms": {
                "field": "title",
                "order": "asc"
              }
            }
          }
        ]
      },
      "aggs": {
        "hits": {
          "top_hits": {
            "size": 100
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在响应中,您将看到并after_key构造:

  "after_key": {
    "store": "http://google.com1087",
    "status": "OK1087",
    "title": "Titanic1087"
  },
Run Code Online (Sandbox Code Playgroud)

这是您需要在后续查询中使用的某种游标,如下所示:

{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 100,
        "sources": [
          {
            "store": {
              "terms": {
                "field": "store_url"
              }
            }
          },
          {
            "status": {
              "terms": {
                "field": "status",
                "order": "desc"
              }
            }
          },
          {
            "title": {
              "terms": {
                "field": "title",
                "order": "asc"
              }
            }
          }
        ],
        "after": {
          "store": "http://google.com1087",
          "status": "OK1087",
          "title": "Titanic1087"
        }
      },
      "aggs": {
        "hits": {
          "top_hits": {
            "size": 100
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

它会给你接下来的 100 个桶。希望这有帮助。

更新

如果您想知道总共有多少个桶,composite聚合不会给您这个数字。但是,由于composite聚合只不过是其源中所有字段的笛卡尔积,因此您还可以通过返回]基数]( https://www.elastic.co/guide/ en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.htmlcomposite聚合中使用的每个字段并将它们相乘。

  "aggs": {
    "my_buckets": {
      "composite": {
        ...
      }
    },
    "store_cardinality": {
      "cardinality": {
        "field": "store_url"
      }
    },
    "status_cardinality": {
      "cardinality": {
        "field": "status"
      }
    },
    "title_cardinality": {
      "cardinality": {
        "field": "title"
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

store_cardinality然后,我们可以通过将、status_cardinalitytitle_cardinality中得到的数字相乘,或者至少是其一个很好的近似值来获得桶的总数(它在高基数字段上效果不佳,但在低基数字段上效果很好)。