Elasticsearch嵌套数组的多个过滤条件

时间:2019-08-08 18:47:36

标签: c# elasticsearch filter nested nest

这个问题可能在某个地方回答了,但我找不到。所以我寻求帮助 我的产品模型具有嵌套的属性列表。像这样

[
    {
        ID: "Product1",
        ...
        Properties: [
            { "Source": "Color", Value: "green"},
            { "Source": "Size",  Value: "2"},
        ]
    },
    {
        ID: "Product2",
        ...
        Properties: [
            { "Source": "Color", Value: "blue"},
            { "Source": "Size", Value: "2"},
        ]
    },
    {
        ID: "Product3",
        ....
        Properties: [
            { "Source": "Color", Value: "red"},
            { "Source": "Size", Value: "1"},
        ]
    },
]

索引映射:

"properties" : {
        "type" : "nested",
        "properties" : {
          "source" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "value" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      },

我需要搜索查询才能找到颜色为绿色或蓝色且尺寸为2的产品。

我为我的搜索请求创建了此查询,但它将返回空结果。

       new Nest.NestedQuery
            {
                Path = new Nest.Field("properties"),
                Query = new Nest.BoolQuery() {
                    Must = new Nest.QueryContainer[] {
                      new Nest.BoolQuery()
                      {
                          Must = new Nest.QueryContainer[] {
                            new Nest.TermQuery()
                            {
                                Field = new Nest.Field("properties.source.keyword"),
                                Value = "Color"
                            },
                            new Nest.TermsQuery()
                            {
                                Field = new Nest.Field("properties.value.keyword"),
                                Terms = new[] { "green", "blue"}
                            }
                         }
                      }
                   },
                   new Nest.BoolQuery()
                      {
                          Must = new Nest.QueryContainer[] {
                            new Nest.TermQuery()
                            {
                                Field = new Nest.Field("properties.source.keyword"),
                                Value = "Size"
                            },
                            new Nest.TermsQuery()
                            {
                                Field = new Nest.Field("properties.value.keyword"),
                                Terms = new[] { "2"}
                            }
                         }
                      }
                   }
                }
            }

您能否通过构建这种查询来帮助我弄错了什么? 谢谢

1 个答案:

答案 0 :(得分:2)

尝试用嵌套查询包装每个must子句:

var query = new BoolQuery
{
    Must = new QueryContainer[]
    {
        new NestedQuery
        {
            Path = "properties",
            Query = new BoolQuery()
            {
                Must = new QueryContainer[]
                {
                    new TermQuery()
                    {
                        Field = new Nest.Field("properties.source.keyword"),
                        Value = "Color"
                    },
                    new TermsQuery()
                    {
                        Field = new Nest.Field("properties.value.keyword"),
                        Terms = new[] { "green", "blue"}
                    }
                }
            }
        },
        new NestedQuery
        {
            Path = "properties",
            Query = new BoolQuery()
            {
                Must = new QueryContainer[]
                {
                    new TermQuery()
                    {
                        Field = new Nest.Field("properties.source.keyword"),
                        Value = "Size"
                    },
                    new TermsQuery()
                    {
                        Field = new Nest.Field("properties.value.keyword"),
                        Terms = new[] {"2"}
                    }
                }
            }
        }
    }
};

完整的示例

class Program
{
    public class Document
    {
        public int Id { get; set; }
        [Nested]
        public List<Property> Properties { get; set; }
    }

    public class Property
    {
        public string Source { get; set; }
        public string Value { get; set; }

        public override string ToString() => $"Source: {Source} Value: {Value}";
    }

    static async Task Main(string[] args)
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var connectionSettings = new ConnectionSettings(pool);
        connectionSettings.DefaultIndex("documents");
        connectionSettings.DisableDirectStreaming();
        connectionSettings.PrettyJson();

        var client = new ElasticClient(connectionSettings);

        var deleteIndexResponse = await client.Indices.DeleteAsync("documents");
        var createIndexResponse = await client.Indices.CreateAsync("documents", d => d
            .Map(m => m.AutoMap<Document>()));

        var indexDocument = await client
            .IndexDocumentAsync(new Document
            {
                Id = 1, 
                Properties = new List<Property>
                {
                    new Property {Source = "Color", Value = "green"},
                    new Property {Source = "Size", Value = "2"},
                }
            });
        indexDocument = await client
            .IndexDocumentAsync(new Document
            {
                Id = 2, 
                Properties = new List<Property>
                {
                    new Property {Source = "Color", Value = "blue"},
                    new Property {Source = "Size", Value = "2"},
                }
            });
        indexDocument = await client
            .IndexDocumentAsync(new Document
            {
                Id = 3, 
                Properties = new List<Property>
                {
                    new Property {Source = "Color", Value = "red"},
                    new Property {Source = "Size", Value = "1"},
                }
            });

        var refreshAsync = client.Indices.RefreshAsync();

        var query = new BoolQuery
        {
            Must = new QueryContainer[]
            {
                new NestedQuery
                {
                    Path = "properties",
                    Query = new BoolQuery()
                    {
                        Must = new QueryContainer[]
                        {
                            new TermQuery()
                            {
                                Field = new Nest.Field("properties.source.keyword"),
                                Value = "Color"
                            },
                            new TermsQuery()
                            {
                                Field = new Nest.Field("properties.value.keyword"),
                                Terms = new[] {"green", "blue"}
                            }
                        }
                    }
                },
                new NestedQuery
                {
                    Path = "properties",
                    Query = new BoolQuery()
                    {
                        Must = new QueryContainer[]
                        {
                            new TermQuery()
                            {
                                Field = new Nest.Field("properties.source.keyword"),
                                Value = "Size"
                            },
                            new TermsQuery()
                            {
                                Field = new Nest.Field("properties.value.keyword"),
                                Terms = new[] {"2"}
                            }
                        }
                    }
                }
            }
        };

        var response = client.Search<Document>(s => s.Query(q => query));

        foreach (var document in response.Documents)
        {
            Console.WriteLine($"Id: {document.Id}");
            document.Properties.ForEach(Console.WriteLine);
            Console.WriteLine();
        }
    }
}

打印:

Id: 1
Source: Color Value: green
Source: Size Value: 2

Id: 2
Source: Color Value: blue
Source: Size Value: 2

希望有帮助。

相关问题