【问题标题】:Matching multiple phrases to one field in Elastic Search将多个短语匹配到 Elastic Search 中的一个字段
【发布时间】:2020-11-19 16:02:42
【问题描述】:

我已经用 C# 构建了一个应用程序,它可以搜索我的 Elasticsearch 文档,并且使用此代码一切正常......

List<AuditLog> resultsList = Client.SearchAsync<AuditLog>(s => s
    .From(0)
    .Take(noRows)
    .Query(q => q
        .Bool(b => b
            .Must(mu => mu.MatchPhrase(mp => mp.Field("audit_Event").Query(auditEvents)),
                mu => mu.Match(ma => ma.Field(field).Query(value))
             )
          )
     )).Result.Documents.ToList();

这一切都很好,但有一个新要求是针对多个短语搜索 audit_Event 字段,例如“用户登录”、“添加员工”等

我找到了对 multi_match 的引用,但这似乎与跨多个字段而不是在一个字段中搜索多个值更相关。

根据下面的讨论,TermQuery 似乎可以完成这项工作,但不会返回任何值。有什么想法吗?

QueryContainer queryAnd = new TermQuery() { Field = "audit_Application", Value = "MyApplication" };
QueryContainer queryOr = new TermQuery() { Field = "audit_Event", Value = "Employee Inserted" };
queryOr |= new TermQuery() { Field = "audit_Event", Value = "Employee Updated" }; 
QueryContainer queryMain = queryAnd & queryOr;

resultsList = Client.SearchAsync<AuditLog>(s => s
    .From(0)
    .Take(noRows)
    .Query(q => q
        .Bool(b => b
            .Must(queryMain)
        )
    )).Result.Documents.ToList();

我还使用 Kibana 检查了两个查询,第一个返回数据,但第二个没有,现在想知道数据的索引方式是否有问题....

GET auditlog/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match_phrase": {
            "audit_Event": "Employee Updated"
          }
        },
        {
          "match_phrase": {
            "audit_Event": "Employee Inserted"
          }
        }
      ]
    }
  }
}

GET auditlog/_search
{
  "query" : {
    "terms": {
        "audit_Event": ["Employee Updated","Employee Inserted"]
    }
  }
}

【问题讨论】:

  • 你需要这样的东西吗? stackoverflow.com/a/63972341/1068246
  • 查看了这一点,这将起作用,因为它允许我根据用户选择的内容以编程方式构建查询,但不幸的是它不返回任何值。相应地修改了主要问题

标签: c# elasticsearch nest


【解决方案1】:

根据您对OR 查询按预期工作的陈述,以下是您可以使用NEST 构建查询的一种方式。您可以根据需要进行任何特定的修改。

这段代码的sn-p负责触发搜索调用

var searchDescriptor = new SearchDescriptor<AuditLog>()
    .Query(q => Blah(auditEventsList))
    .From(0)
    .Take(noRows);
    // other methods you want to chain here

var response = Client.searchAsync<AuditLog>(searchDescriptor);

搜索查询在此处生成。注意SHOULD 的使用以及对另一个负责动态生成match_phrase 查询的方法的调用。

private static QueryContainer Blah(List<string> auditEventsList)
{
    return new QueryContainerDescriptor<AuditLog>().Bool(
        b => b.Should(
            InnerBlah(auditEventsList)
        )
    );
}

此方法生成match_phrase 查询数组,这些查询将传递给上述sn-p 中的should。这些是通过迭代收到的所有审计事件生成的。

private static QueryContainer[] InnerBlah(List<string> auditEventsList)
{
    QueryContainer orQuery = null;
    List<QueryContainer> queryContainerList = new List<QueryContainer>();
    foreach(var item in auditEventsList)
    {
        orQuery = new MatchPhraseQuery { Field = "audit_Event", Query = item };
        queryContainerList.Add(orQuery);
    }
    return queryContainerList.ToArray();
}

【讨论】:

    【解决方案2】:

    如果您想将多个短语与单个字段匹配,则可以使用bool query 与 match_phrase 的以下组合

    {
      "query": {
        "bool": {
          "must": [
            {
              "match_phrase": {
                "audit_Event": "User Login"
              }
            },
            {
              "match_phrase": {
                "audit_Event": "Add Employee"
              }
            }
          ]
        }
      }
    }
    

    【讨论】:

    • @adig14 你有机会看一下我的回答吗,期待得到你的反馈:)
    • 这适用于 Kibana,但需要能够根据用户选择以编程方式构建查询。
    • @adig14 我不熟悉 c# :|,但是如果我的回答对您有任何帮助,请不要忘记为我的回答投票 :)
    • 谢谢,您的回答给了我一种在 Kibana 中测试的方法,但“必须”必须是“应该”,否则无法满足条件。
    【解决方案3】:

    请试试这个:

    QueryContainer queryOr = new MatchPhraseQuery() { Field = "audit_Event", Query = "Employee Inserted" };
            queryOr |= new MatchPhraseQuery() { Field = "audit_Event", Query = "Employee Updated" };
            ISearchResponse<AuditLog> resultAuditLog = Client.Search<AuditLog>(s => s
                        .RequestConfiguration(r => r.DisableDirectStreaming())
                        .From(0)
                        .Size(100)
                        .Query(q2 => q2
                            .Bool(b => b
                            .Should(queryOr))
                        )
            );
    

    【讨论】:

    • 这也不起作用。可能是数据在elasticsearch中的存储方式吗?在 Kibana 中做.. GET auditlog/_search { "query" : { "match": { "audit_Event": "Employee Inserted" } } } 返回数据但正在做.. GET auditlog/_search { "query" : { " terms": { "audit_Event": ["Employee Inserted"] } } } 没有。
    • audit_Event 字段包含我们搜索的相同单词?如果不是,您应该使用WildcardQuery*Employee Updated* 我已经编辑了答案。
    • 应该与短语“Employee Inserted”或“Employee Updated”完全匹配
    • 该字段是否有任何分析器?
    • 没有特别添加一个,所以只会是默认的。在 Google 上查看它提到了将“索引”与“条款”一起使用。我是否应该创建一个包含所有“event_Audit”值的索引,以便条款可以找到它们?
    猜你喜欢
    • 2015-07-13
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    相关资源
    最近更新 更多