计算经过过滤和排序的查询的结果

时间:2019-03-15 14:31:23

标签: elasticsearch

在ES中执行此等效操作遇到麻烦:

SELECT COUNT(*)
FROM
(
    SELECT current_place
    FROM `request`
    WHERE user_id = '3'
    ORDER BY asked_at DESC
    LIMIT 10
) sr1
WHERE current_place = '4'

目标是获取用户的10条最近记录(asked_at是一个时间戳字段),并计算有current_place = '4'条记录的记录数量

在Elasticsearch中,我没有进行排序,因为我什至没有成功过滤10个元素:

GET /index/type/_search
{
  "size": 10,
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "user_id": 3
          }
        },
        {
          "term": {
            "current_place": 4
          }
        }
      ]
    }
  }
}

哪个给我:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 54,
    "max_score" : 0.0,
    "hits" : [
      ... truncated, 10 records ...
    ]
  }
}

如何对排序和过滤后的数据进行计数?

编辑:

以下是数据示例:

1 | 2019-03-13 18:28:17
1 | 2019-01-15 16:48:30
1 | 2019-01-15 16:25:32
1 | 2019-01-15 16:19:36
1 | 2019-01-15 15:43:33
1 | 2019-01-15 15:42:05
4 | 2018-11-22 14:14:03
1 | 2018-09-11 11:36:05
4 | 2018-09-11 11:00:49
1 | 2018-08-31 11:19:17 -> 10th line
1 | 2018-08-31 11:19:17
1 | 2018-08-31 11:09:32
1 | 2018-08-27 10:19:04
4 | 2018-08-23 11:56:27

SQL查询返回2

1 个答案:

答案 0 :(得分:1)

如果您具有该特定索引的 n 个分片,那么对于Elasticsearch来说是不可能的。

因此,基本上有一个名为terminate after的功能可用于请求正文搜索,该功能仅考虑每个 shard 中的 n个文档。是的,它适用于分片级别。

假设我的索引具有5个分片,我想可以在下面的更新查询中使用值2来查看是否只有10个文档(5个分* 2个文档)检索到了,但是那样行不通,因为一个分片可能只返回1文档,而其余部分返回2,最终我最终对9个文档应用了聚合查询。

每个分片的文档减少了,排序结果本身可能无法获取正确的前10个文档。

汇总查询

POST <your_index_name>/_search
{  
   "size":0,
   "terminate_after":2,
   "query":{  
      "bool":{  
         "filter":[  
            {  
               "term":{  
                  "user_id":101
               }
            }
         ]
      }
   },
   "sort":[  
      {  
         "asked_at":{  
            "order":"desc"
         }
      }
   ],
   "aggs":{  
      "filter_current_place":{  
         "filter":{  
            "term":{  
               "current_place":4
            }
         },
         "aggs":{  
            "requiredCount":{  
               "value_count":{  
                  "field":"current_place"
               }
            }
         }
      }
   }
}

以下是我的回复:

响应

{
  "took" : 2,
  "timed_out" : false,
  "terminated_early" : true,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 9,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "filter_current_place" : {
      "doc_count" : 2,
      "requiredCount" : {
        "value" : 2
      }
    }
  }
}

请注意,尽管提及我希望每个分片考虑2个文档,但命中仅为9。当然,该计数似乎是正确的,因为如问题中所述,第9个文档具有current_place:4。如果它排在第十位呢!

  

这可能是不正确的,而且很清楚这是什么   这将需要在客户端或服务层完成。

如果是这种情况,那么您只需要执行以下查询,并根据客户端/服务层上的前10个文档处理汇总逻辑。

排序查询

POST <your_index_name>/_search
{  
   "size":10,
   "query":{  
      "bool":{  
         "filter":[  
            {  
               "term":{  
                  "user_id":101
               }
            }
         ]
      }
   },
   "sort":[  
      {  
         "asked_at":{  
            "order":"desc"
         }
      }
   ]
}

注意:上面提到的第一个查询通过Elasticsearch实现此目的的唯一可能方法是,您的索引只有single shard,而您使用{{1 }}

尽管从技术上讲这不是,但我希望这会有所帮助!