【问题标题】:How to search dynamic elements of array in ElasticSearch using C# NEST?如何使用 C# NEST 在 ElasticSearch 中搜索数组的动态元素?
【发布时间】:2021-03-29 22:58:57
【问题描述】:

我的弹性搜索中有这些数据,具有这种结构。

如何从这个数组中搜索 firstName、middleName 和 surname?注意:NameDetails 数组长度是动态的。人 A 可能只有一个元素 NameDetails。人 B 可以有 NameDetails 的 3 个元素。

目前,我只能通过gender 进行搜索。我正在使用 NEST nuget C#。这是我的查询。

var response = await _elasticClient.SearchAsync<Person>(s => s
          .Query(q => q
              .Bool(b => b.Must(
                mu => mu
                .Match(m => m
                 .Field(f => f.Gender)
                 .Query(Gender)
                )

                )
              )
          )
        );

在 NEST 中,我尝试使用此代码但未返回任何结果。

        var response = _elasticClient.Search <Model.Entities.Split.Person.Person> (s => s
            .Index("person")
            .Query(q => q
                .Match(m => m
                    .Field(f => f.NameDetails.Name[0].NameValue.FirstName)
                    .Query("Fawsu")
                )
            )
        );

但如果我直接在 ElasticSearch 上运行 DSL 查询并使用下面的查询,它会返回结果。

GET /person/_search
{
  "query": {
    "match": {
          "nameDetails.nameValue.firstName": {
            "query": "Fawsu"
          }
        }
    }
  }
}

GET /person/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "fuzzy": {
            "nameDetails.nameValue.surname": {
              "value": "Pibba",
              "fuzziness": "AUTO"
            }
          }
        },
        
        {
          "fuzzy": {
            "nameDetails.nameValue.firstName": {
              "value": "Fawsu",
              "fuzziness": "AUTO"
            }
          }
        }
      ]
    }
  }
}

【问题讨论】:

    标签: c# elasticsearch nest


    【解决方案1】:

    看看它是如何映射到 POCO 的很有用

    public class Person
    {
        public string Gender { get; set; }
        public string ActiveStatus { get; set; }
        public string Deceased { get; set; }
        public List<Name> NameDetails { get; set; }
    }
    
    public class Name
    {
        public List<NameValue> NameValue { get; set; }
        public string NameType { get; set; }
    }
    
    public class NameValue
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
    }
    

    (您可以将其中一些字段映射为字符串以外的类型,我将把它作为练习留给读者)。

    搜索名字

    var client = new ElasticClient();
    
    
    var response = client.Search<Person>(s => s
        .Index("people")
        .Query(q => q
            .Match(m => m
                .Field(f => f.NameDetails[0].NameValue[0].FirstName)
                .Query("Fawsu")
            )
        )
    );
    

    产生查询

    POST http://localhost:9200/people/_search?pretty=true&typed_keys=true 
    {
      "query": {
        "match": {
          "nameDetails.nameValue.firstName": {
            "query": "Fawsu"
          }
        }
      }
    }
    

    .Field(f =&gt; f...) 中的表达式是用于构建"nameDetails.nameValue.firstName" 路径的表达式,它将在any名字值和名字细节的名字中寻找匹配。它使用索引器的事实意味着它以名字详细信息的名字值为目标,而只是一种遍历对象图以构建表达式的方法。

    要构建复合查询以定位相同名称值的多个值,NameNameValue 都需要为mapped as nested data types,然后将使用嵌套查询。

    对于单个字段

    var response = client.Search<Person>(s => s
        .Index("people")
        .Query(q => q
            .Nested(n => n
                .Path(f => f.NameDetails)
                .Query(nq => nq
                    .Nested(nn => nn
                        .Path(f => f.NameDetails[0].NameValue)
                        .Query(nnq => nnq
                            .Match(m => m
                                .Field(f => f.NameDetails[0].NameValue[0].FirstName)
                                .Query("Fawsu")
                            )
                        )
                    )
                )
            )
        )
    );
    

    对于多个字段

    var response = client.Search<Person>(s => s
        .Index("people")
        .Query(q => q
            .Nested(n => n
                .Path(f => f.NameDetails)
                .Query(nq => nq
                    .Nested(nn => nn
                        .Path(f => f.NameDetails[0].NameValue)
                        .Query(nnq => nnq
                            .Bool(b => b
                                .Must(m => m
                                    .Match(m => m
                                        .Field(f => f.NameDetails[0].NameValue[0].FirstName)
                                        .Query("Fawsu")
                                    ), m => m
                                    .Match(m => m
                                        .Field(f => f.NameDetails[0].NameValue[0].LastName)
                                        .Query("Pibba")
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
    );
    

    后者导致查询

    POST http://localhost:9200/people/_search?pretty=true&typed_keys=true 
    {
      "query": {
        "nested": {
          "path": "nameDetails",
          "query": {
            "nested": {
              "path": "nameDetails.nameValue",
              "query": {
                "bool": {
                  "must": [
                    {
                      "match": {
                        "nameDetails.nameValue.firstName": {
                          "query": "Fawsu"
                        }
                      }
                    },
                    {
                      "match": {
                        "nameDetails.nameValue.lastName": {
                          "query": "Pibba"
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
    

    【讨论】:

    • 解决方案看起来不错。只是想知道,如何检查它是否映射为嵌套数据类型?
    • 您可以获取索引映射并检查字段的类型:elastic.co/guide/en/elasticsearch/reference/current/…。这是 NEST 的获取映射 API 测试:github.com/elastic/elasticsearch-net/blob/…。它在字段上使用访问者来断言映射类型计数,但您可以直接在响应上遍历属性并断言类型
    • 请复制和粘贴代码/文本而不是屏幕截图 - 它更易于阅读、使用并且可索引/可搜索。看起来nameDetailsnameValue 都映射为"object",如果您想单独搜索单个字段,这是可以的,但如果您想跨相同nameDetail 或@ 的字段进行搜索,这将不起作用987654340@.
    • 表达式.Field(f =&gt; f.NameDetails[0].NameValue[0].FirstName) 将搜索所有名称值的所有名字和所有名称详细信息
    • 哪个查询?这里的例子有帮助吗?
    【解决方案2】:

    如果您想搜索以下内容:

    firstName == "John" AND middleName == "Ben" AND lastName == "smith"

    然后你可以使用TermQuery搜索firstNamemiddleNamelastName

    我比较熟悉Object Initializer Syntax(需要using static Nest.Infer

    using static Nest.Infer;
    
    var query = new TermQuery
    {
        Name = "my firstName query",
        Field = Field<Person>(p => p.firstName),
        Value = "John"
    };
    

    您需要为 middleNamelastName 再编写 2 个查询,然后为 AND 所有这些查询。


    如果您想搜索以下内容:

    firstName == "John" OR middleName == "John" OR lastName == "John"

    那么你可以使用Multi-match Query:

    using static Nest.Infer;
    
    var query = new MultiMatchQuery
    {
        Name = "My Multi-match query",
        Fields = Field<Person>(p => p.firstName, 1.1) // 1.1 is boost (default is 1)
            .And<AdDocument>(p => p.middleName, 1)
            .And<AdDocument>(p => p.lastName, 1)
        Query = "John"
        //Fuzziness = Fuzziness.Auto
    };
    

    【讨论】:

    • 但是名字嵌套在nameDetails中。基本上,一个人可以有很多组名字。例如,我发布的人有 2 组名字,firstName:Fawsu 和 surName:Pibba 和 firstName:Fausu 和 surName:Pibba。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2018-05-29
    • 2020-09-11
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 2020-11-28
    相关资源
    最近更新 更多