通过查询其他文档对对象进行 Elasticsearch 聚合

Elasticsearch Aggregation on objects by query on other documents

假设我有一个索引,其中包含代表讨论中消息的文档。
该文档拥有一个 discussionId 属性。 (它还有自己的ID"that represent MessageId")

现在,我需要找到所有没有匹配查询的文档(消息)的 discussionId。
例如:
"Find all discussionIds , that have no message that contains the text 'YO YO'"

我该怎么做?

class与此类似:

  public class Message
  {
     public string Id{get;set}
     public string DiscussionId {get;set}
     public string Text{get;set}
  }

您只需包装会找到 matches for the phrase "YO YO" in a bool query must_not clause.

的查询

有 NEST

client.Search<Message>(s => s
    .Query(q => q
        .Bool(b => b
            .MustNot(mn => mn
                .MatchPhrase(m => m
                    .Field(f => f.Text)
                    .Query("YO YO")
                )
            )
        )
    )
);

其中 operator overloading 可以缩短为

client.Search<Message>(s => s
    .Query(q => !q
        .MatchPhrase(m => m
            .Field(f => f.Text)
            .Query("YO YO")
        )
    )
);

两者都产生查询

{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "text": {
              "type": "phrase",
              "query": "YO YO"
            }
          }
        }
      ]
    }
  }
}

为了只有returnDiscussionId值,可以使用source filtering

client.Search<Message>(s => s
    .Source(sf => sf
        .Includes(f => f
            .Field(ff => ff.DiscussionId)
        )
    )
    .Query(q => !q
        .MatchPhrase(m => m
            .Field(f => f.Text)
            .Query("YO YO")
        )
    )
);

而且,如果你想得到它们,你可以使用 scroll API

var searchResponse = client.Search<Message>(s => s
    .Scroll("1m")
    .Source(sf => sf
        .Includes(f => f
            .Field(ff => ff.DiscussionId)
        )
    )
    .Query(q => !q
        .MatchPhrase(m => m
            .Field(f => f.Text)
            .Query("YO YO")
        )
    )
);

// fetch the next batch of documents, using the scroll id returned from
// the previous call. Do this in a loop until no more docs are returned.
searchResponse = client.Scroll<Message>("1m", searchResponse.ScrollId);