如何在Elasticsearch中创建文档子集并对子集执行查询?

时间:2018-01-21 23:45:36

标签: java elasticsearch elasticsearch-5

原因是我们有一个API从客户端接收查询参数并构建一个Elasticsearch查询。但是,根据用户的类型(无论是财务顾问还是投资者等),我们必须应用更多条件才能限制搜索。遗憾的是,我们无法对索引的结构进行任何更改(即添加额外的列),这是因为索引不是由我们管理的,我们的API没有关于索引的信息,除了可配置的列名。

所以这是一个例子。我们会收到一封基于“investorDateOfBirth”和“financialAdviserId”进行搜索的请求,因为搜索来自一位顾问,我们会以编程方式添加此条件:

  

financialAdviserId必须为'123'(当前用户的ID)

所以最终的查询变为:

{
  "bool" : {
    "must" : [
      {
        "term" : {
          "financialAdviserId" : {
            "value" : "123",
            "boost" : 1.0
          }
        }
      }
    ],
    "should" : [
      {
        "term" : {
          "investorDateOfBirth" : {
            "value" : "1987-11-12",
            "boost" : 1.0
          }
        }
      },
      {
        "term" : {
          "financialAdviserId" : {
            "value" : "123",
            "boost" : 1.0
          }
        }
      }
    ],
    "disable_coord" : false,
    "adjust_pure_negative" : true,
    "boost" : 1.0
  }
}

正如您所看到的,有2个'financialAdviserId',一个是根据请求查询参数以编程方式构建的,另一个('must')是根据当前用户添加的,但是如您所知,这将返回具有指定{的那些{1}}以及顾问ID为123的所有其他项目(包括那些没有相同DOB的项目)

所以想象一下索引中有3条记录:

investorDateOfBirth

对于上面的查询,结果是所有3行,这不是我们想要的结果,但是,对于以下查询,它返回仅第一行,这是期望:

| investorDateOfBirth | financialAdviserId | investorId |
| "1987-11-12"        | 123                | 111        |
| "1900-11-12"        | 123                | 222        |
| "1900-11-12"        | 123                | 333        |

如何解决这个问题?我们如何更改第一个查询以获得与第二个查询(返回第一行)相同的结果。

只是为了让您知道,我们无法使{ "bool" : { "must" : [ { "term" : { "financialAdviserId" : { "value" : "123", "boost" : 1.0 } } } ], "should" : [ { "term" : { "investorDateOfBirth" : { "value" : "1987-11-12", "boost" : 1.0 } } } ], "disable_coord" : false, "adjust_pure_negative" : true, "boost" : 1.0 } } 无法搜索,因为还有其他实体可以搜索这些列?有没有办法创建一个子集(在我们的例子中是financialAdviserId为123的子集),然后针对该子集从客户端执行请求的查询?

我们在financialAdviserId

中使用Elasticsearch v5.5.3

1 个答案:

答案 0 :(得分:2)

你快到了。为了获得预期的行为,您可以将一个bool嵌套到另一个中:

{
"bool": {
  "must": [
    {
      "term": {
        "financialAdviserId": {
          "value": "123"
        }
      }
    },
    {
      "bool": {
        "should": [
          {
            "term": {
              "investorDateOfBirth": {
                "value": "1987-11-12"
              }
            }
          },
          {
            "term": {
              "financialAdviserId": {
                "value": "123"
              }
            }
          }
        ]
      }
    }
  ]
}

(我删除了boost和其他详细信息,以使这个想法更加清晰。)

为什么问题中的第一个查询不起作用

现在让我解释为什么初始查询不起作用。

您在bool查询的同一个实例中使用了mustshould。在这种情况下记录的行为如下:

  

should

     

如果bool查询位于查询上下文中且有mustfilter   然后一个文件将匹配bool查询,即使没有   如果查询匹配。

(这也是Federico使用filter的建议无法解决问题的原因。)

实际上,您应用的查询具有以下逻辑含义:

    query_restricting_set_of_docs AND (user_query or True)

你正在寻找这个:

    query_restricting_set_of_docs AND user_query

在您的情况下,user_query看起来像这样:

    query_restricting_set_of_docs OR some_other_query

给我们带来了最后的表达:

    query_restricting_set_of_docs AND (
        query_restricting_set_of_docs OR some_other_query
    )

转换为ES bool查询,如下所示:

{
  "bool": {
    "must": [
      {
        ...query_restricting_set_of_docs
      },
      {
        "bool": {
          "should": [
            {
              ...query_restricting_set_of_docs
            },
            {
              ...other_query
            }
          ]
        }
      }
    ]
  }
}

关于query and filter context

的说明

过滤器和查询上下文之间的主要区别是:

  • 查询上下文计算相关性得分,结果未缓存
  • 过滤器上下文不计算分数但结果已缓存

缓存部分可以加快搜索速度,但如果没有相关性分数,您将无法首先显示更多相关文档。在您的情况下,您可能希望将query_restricting_set_of_docs放入过滤器上下文中。

为此,您可以使用以下查询:

{
  "bool": {
    "must": [
      {
        "bool": {
          "filter": [
            {
              "term": {
                "financialAdviserId": {
                  "value": "123"
                }
              }
            }
          ]
        }
      },
      {
        "bool": {
          "should": [
            {
              "term": {
                "investorDateOfBirth": {
                  "value": "1987-11-12"
                }
              }
            },
            {
              "term": {
                "financialAdviserId": {
                  "value": "123"
                }
              }
            }
          ]
        }
      }
    ]
  }
}

在这里,我们将query_restricting_set_of_docs打包到另一个bool filter,从而实现过滤部分的过滤器上下文。

如果您控制了索引,并且您希望限制索引的子集很少,则可以使用Filtered Aliases,这基本上会为执行的所有查询添加指定的filter反对那个别名。

希望有所帮助!