如何通过字段值限制ElasticSearch结果?

时间:2016-02-19 20:52:55

标签: elasticsearch filter aggregate full-text-indexing

我们有一个系统使用mapper附件插件对ElasticSearch中的文档进行索引。除了索引文档之外,我还存储了一些基本信息,例如它是否与申请人或员工相关联,他们的姓名以及他们在系统中分配的ID。运行的查询在遇到ES时可能看起来像这样:

{
  "size" : 100,
  "query" : {
    "query_string" : {
      "query" : "software AND (developer OR engineer)",
       "default_field" : "fileData"
    }
  },
  "_source" : {
    "includes" : [ "applicant.*", "employee.*" ]
  }
}

并得到我的结果:

"hits": [100]
    0:  {
      "_index": "careers"
      "_type": "resume"
      "_id": "AVEW8FJcqKzY6y-HB4tr"
      "_score": 0.4530588
      "_source": {
      "applicant": {
        "name": "John Doe"
        "id": 338338
        }
      }
    }...

我正在尝试做的是限制结果,因此如果ID为338338的John Doe在系统中有三个与查询匹配的不同简历,我只返回一个匹配,最好是得分最高的一个(尽管只要我能找到这个人,那就不那么重要了。我一直在尝试使用过滤器和聚合的不同选项,但我没有偶然发现这样做的方法。

我可以在应用程序中采用各种方法,在我得到结果后调用ES来解决这个问题,但是如果我可以在ES方面做到这一点,那将是更可取的。由于我限制查询说100个结果,我想找回100个人,而不是取回100个结果,然后发现其中25%是与同一个人绑定的文档。

3 个答案:

答案 0 :(得分:0)

你想要做的是获得前100个唯一记录的聚合,然后是要求" top_hits"的子聚合。这是我系统的一个例子。在我的例子中我是:

  1. 将结果大小设置为0,因为我只关心聚合
  2. 将聚合的大小设置为100
  3. 对于每个聚合,获得前1个结果
  4. GET index1/type1/_search { "size": 0, "aggs": { "a1": { "terms": { "field": "input.user.name", "size": 100 }, "aggs": { "topHits": { "top_hits": { "size": 1 } } } } } }

答案 1 :(得分:0)

使用上面的答案和IanGabes的链接,我能够重新构建我的搜索:

            int a, b, c, d, e, f, g, h, i, j, k, l;

// conversion of whole value in text box to single integers
            char[] digits_array = TextBox1.Text.ToCharArray(); 

//Now just declare each variable as you want there are several ways to do it    
            a = int.Parse(digits_array[0].ToString());
            b = int.Parse(digits_array[1].ToString());
            c = int.Parse(digits_array[2].ToString());
            d = int.Parse(digits_array[3].ToString());
            e = int.Parse(digits_array[4].ToString());
            f = int.Parse(digits_array[5].ToString());
            g = int.Parse(digits_array[6].ToString());
            h = int.Parse(digits_array[7].ToString());
            i = int.Parse(digits_array[8].ToString());
            j = int.Parse(digits_array[9].ToString());
            k = int.Parse(digits_array[10].ToString());
            l = int.Parse(digits_array[11].ToString());

这让我回到了两个桶,一个包含所有申请人ID并且匹配文档中的得分最高,以及员工也一样。该脚本只不过是碎片上的一个groovy脚本,其中包含' _score'作为内容。

答案 2 :(得分:0)

有一种更简单的方法,可以利用Elasticsearch的折叠功能来完成@ckasek想要做的事情。

字段折叠,如Elasticsearch docs中所述:

允许折叠基于字段值的搜索结果。折叠是通过每个折叠键仅选择排序最靠前的文档来完成的。

基于上面的原始查询示例,您将像这样修改它:

{
  "size" : 100,
  "query" : {
    "query_string" : {
      "query" : "software AND (developer OR engineer)",
       "default_field" : "fileData"
    }
  },
  "collapse": {
    "field": "id",
  },
  "_source" : {
    "includes" : [ "applicant.*", "employee.*" ]
  }
}