ElasticSearch - 仅搜索与搜索响应中的所有顶级字段匹配的嵌套对象

时间:2016-11-24 07:07:33

标签: elasticsearch

让我说我有以下文件:

{
    id: 1,
    name: "xyz",
    users: [
        {
            name: 'abc',
            surname: 'def'
        },
        {
            name: 'xyz',
            surname: 'wef'
        },
        {
            name: 'defg',
            surname: 'pqr'
        }
    ]
}

我想只获取匹配搜索响应中所有顶级字段的嵌套对象。 我的意思是如果我搜索/过滤名称为' abc'的用户,我想要低于响应

{
    id: 1,
    name: "xyz",
    users: [
        {
            name: 'abc',
            surname: 'def'
        }
    ]
}

我该怎么做?

参考:select matching objects from array in elasticsearch

5 个答案:

答案 0 :(得分:14)

如果您拥有除嵌套字段之外的所有根字段,然后只有嵌套字段中匹配的内部匹配,那么我们可以通过指定稍微更复杂的源过滤来重复使用之前的答案参数:

{
  "_source": {
    "includes": [ "*" ],
    "excludes": [ "users" ]
  },
  "query": {
    "nested": {
      "path": "users",
      "inner_hits": {        <---- this is where the magic happens
        "_source": [
          "name", "surname"
        ]
      },
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "users.name": "abc"
              }
            }
          ]
        }
      }
    }
  }
}

答案 1 :(得分:0)

也许迟到了,我使用嵌套排序来限制嵌套关系中的元素,这里是一个例子:

"sort": {
    "ouverture.periodesOuvertures.dateDebut": {
      "order": "asc",
      "mode": "min",
      "nested_filter": {
        "range": {
          "ouverture.periodesOuvertures.dateFin": {
            "gte": "2017-08-29",
            "format": "yyyy-MM-dd"
          }
        }
      },
      "nested_path": "ouverture.periodesOuvertures"
    }
  },

自5.5 ES(我认为)你可以在嵌套查询上使用过滤器。 这里是我使用的嵌套查询过滤器的示例:

{
            "nested": {
              "path": "ouverture.periodesOuvertures",
              "query": {
                "bool": {
                  "must": [
                    {
                      "range": {
                        "ouverture.periodesOuvertures.dateFin": {
                          "gte": "2017-08-29",
                          "format": "yyyy-MM-dd"
                        }
                      }
                    },
                    {
                      "range": {
                        "ouverture.periodesOuvertures.dateFin": {
                          "lte": "2017-09-30",
                          "format": "yyyy-MM-dd"
                        }
                      }
                    }
                  ],
                  "filter": [
                    {
                      "range": {
                        "ouverture.periodesOuvertures.dateFin": {
                          "gte": "2017-08-29",
                          "format": "yyyy-MM-dd"
                        }
                      }
                    },
                    {
                      "range": {
                        "ouverture.periodesOuvertures.dateFin": {
                          "lte": "2017-09-30",
                          "format": "yyyy-MM-dd"
                        }
                      }
                    }
                  ]
                }
              }
            }
          }

希望这可以提供帮助;)

另外,如果您的ES不在最后一个版本(5.5)中,则inner_hits会降低您的查询速度Including inner hits drastically slows down query results

答案 2 :(得分:0)

https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-request-inner-hits.html#nested-inner-hits-source

  "inner_hits": {
    "_source" : false,
    "stored_fields" : ["name", "surname"]
  }

,但是您可能需要更改映射以将这些字段设置为“ stored_fields”,否则可以使用 “ inner_hits”:{} 以获得不那么完美的结果。

答案 3 :(得分:0)

您可以发出这样的请求,但响应将包含以 _ 开头的内部字段

{
  "_source": {
    "includes": [ "*" ],
    "excludes": [ "users" ]
  },
  "query": {
    "nested": {
      "path": "users",
      "inner_hits": {},
      "query": {
        "bool": {
          "must": [
            { "match": { "users.name":  "abc" }}
          ]
        }
      }
    }
  }
}

答案 4 :(得分:0)

在我的一个项目中,我的期望是检索具有特定标签的独特对话消息文本(内部字段,如 messages.text)。所以我没有使用inner_hits,而是使用如下聚合,

final NestedAggregationBuilder aggregation = AggregationBuilders.nested("parentPath", "messages").subAggregation(AggregationBuilders.terms("innerPath").field("messages.tag"));
        final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .addAggregation(aggregation).build();
        final Aggregations aggregations = elasticsearchOperations.search(searchQuery, Conversation.class).getAggregations();
        final ParsedNested parentAgg = (ParsedNested) aggregations.asMap().get("parentPath");
        final Aggregations childAgg = parentAgg.getAggregations();
        final ParsedStringTerms childParsedNested = (ParsedStringTerms) childAgg.asMap().get("innerPath");
        // Here you will get unique expected inner fields in key part.
        Map<String, Long> agg = childParsedNested.getBuckets().stream().collect(Collectors.toMap(Bucket::getKeyAsString, Bucket::getDocCount));