elasticsearch BitSet Filter还是其他什么?

时间:2015-03-20 11:19:20

标签: elasticsearch

有一个“人”类型的文件,有两个字段“城市”和“性别”,例如

person : {
  "name" : "x",
  "city" : "stockholm",
  "gender" : "m"
}

示例数据:

person: {name: "x", "city" : "stockholm", "gender" : "m"}
person: {name: "y", "city" : "stockholm", "gender" : "m"}
person: {name: "z", "city" : "stockholm", "gender" : "m"}
person: {name: "zz", "city" : "stockholm", "gender" : "f"}
person: {name: "xy", "city" : "uppsala", "gender" : "m"}
person: {name: "xz", "city" : "stockholm", "gender" : "m"}
person: {name: "yy", "city" : "uppsala", "gender" : "f"}

首次质询:选择2名随机的人居住在斯德哥尔摩

    size: 2,
    "query": {
    "function_score": {
      "query": {
        "term": {
          "city": {
            "value": "stockholm"
          }
        }
      },
      "functions": [
        {
          "random_score": {
            "seed": 314159265359
          }
        }
      ]
    }
  }

以上查询的总点击数为5,其中随机选择了2个结果

possible result (As it can be random): 
person: {name: "y", "city" : "stockholm", "gender" : "m"}
person: {name: "zz", "city" : "stockholm", "gender" : "f"}

第二个查询:现在我想选择性别为“m”但第一次查询选择的人。

之类的东西
bool : must [{ 
  term: {
  "gender" : "m"
  }
}]
must_not : [{ /*NOT SELECTED BY FIRST QUERY i.e name = y, zz */}]

result:
person: {name: "x", "city" : "stockholm", "gender" : "m"}        
person: {name: "z", "city" : "stockholm", "gender" : "m"}
person: {name: "xy", "city" : "uppsala", "gender" : "m"}
person: {name: "xz", "city" : "stockholm", "gender" : "m"}

这可以通过弹性搜索中的任何方式实现吗?可能通过过滤器(使用BitSet快速访问文档ID)或dismax查询?

请注意,数据大小以百万为单位,如果我从第一个查询中提取导致数千万的数据,则需要花费大量时间,这在我们的方案中是不可接受的。我只需要计数而不是两个查询中的实际数据。

我不介意在一个查询中尽可能地做,但我不知道该怎么做。

1 个答案:

答案 0 :(得分:0)

我用你的数据做了一个简单的测试用例。

如果查询返回随机数据,则必须进行两次查询 第一个返回n行,你必须取结果的n ids /属性,并从第二个中排除它们

第二个查询可能是(我编写了一个过滤器来排除名为'x'和'zz'的人):

{
   "aggs":{
      "persons":{
         "filter":{
            "bool":{
               "must_not":{
                  "term":{
                     "name":"x"
                  }
               },
               "must_not":{
                  "term":{
                     "name":"zz"
                  }
               }
            }
         },
         "aggs":{
            "gender":{
               "terms":{
                  "field":"gender"
               }
            }
         }
      }
   }
}

按性别分组的结果是

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 7,
    "max_score": 0,
    "hits": [

    ]
  },
  "aggregations": {
    "persons": {
      "doc_count": 5,
      "gender": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "m",
            "doc_count": 4
          },
          {
            "key": "f",
            "doc_count": 1
          }
        ]
      }
    }
  }
}

第二个查询按性别返回计数,不包括上一个查询的两个结果。

对于firt查询,我认为你需要一个不同的随机实现。如果您有数百万行,并且您首先为每个行分配一个随机数,然后按行数对行进行排序,则不可避免地需要花费大量时间。更明智的解决方案是为每个文档使用序列字段,存储它,然后在[序列值的0..max]范围内生成两个随机数。使用这两个数字,您可以非常快速地查询数据并应用第二个查询。使用此解决方案,响应时间会快得多。