原因是我们有一个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
答案 0 :(得分:2)
你快到了。为了获得预期的行为,您可以将一个bool
嵌套到另一个中:
{
"bool": {
"must": [
{
"term": {
"financialAdviserId": {
"value": "123"
}
}
},
{
"bool": {
"should": [
{
"term": {
"investorDateOfBirth": {
"value": "1987-11-12"
}
}
},
{
"term": {
"financialAdviserId": {
"value": "123"
}
}
}
]
}
}
]
}
(我删除了boost
和其他详细信息,以使这个想法更加清晰。)
现在让我解释为什么初始查询不起作用。
您在bool
查询的同一个实例中使用了must
和should
。在这种情况下记录的行为如下:
should
如果
bool
查询位于查询上下文中且有must
或filter
然后一个文件将匹配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_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
反对那个别名。
希望有所帮助!