如何使用嵌套映射对多个索引执行 ElasticSearch 查询

How can I execute ElasticSearch query on multiple indices with nested mapping

我有两个具有以下映射配置的索引

var settings = new ConnectionSettings(new Uri("http://localhost:9200/"));
settings
      .DefaultMappingFor<ManagementIndex>(m => m
          .IndexName("management")
      )
      .DefaultMappingFor<PropertyIndex>(m => m
          .IndexName("apartmentproperty")
      );
var client = new ElasticClient(settings);


1) 属性映射

client.Indices.Create("property", i => i
                .Settings(s => s
                    .NumberOfShards(2)
                    .NumberOfReplicas(0)
                )
                .Map<PropertyIndex>(map => map
                    .AutoMap()
                    .Properties(p => p
                        .Nested<PropertyData>(n => n
                            .Name(c => c.property)
                            .AutoMap()
                            .Properties(pp => pp
                                .Text(c => c
                                    .Name(np => np.city)
                                    .Analyzer("standard")
                                )
                                .Text(c => c
                                    .Name(np => np.market)
                                    .Fields(ff => ff
                                        .Text(tt => tt
                                            .Name(np => np.market)
                                            .Analyzer("standard")
                                        )
                                        .Keyword(k => k
                                            .Name("keyword")
                                            .IgnoreAbove(256)
                                        )
                                    )
                                ).Text(c => c
                                    .Name(np => np.name)
                                    .Analyzer("standard")
                                )

                            )
                        )
                    )
                )
            );

2) 所有者

if (client.Indices.Exists("owner").Exists)
                client.Indices.Delete("owner");

            client.Indices.Create("owner", i => i
                .Settings(s => s
                    .NumberOfShards(2)
                    .NumberOfReplicas(0)
                )
                .Map<OwnerIndex>(map => map
                    .AutoMap()
                    .Properties(p => p
                        .Nested<OwnerProp>(n => n
                            .Name(c => c.owner)
                            .AutoMap()
                            .Properties(pp => pp
                                .Text(c => c
                                    .Name(np => np.market)
                                    .Fields(ff => ff
                                        .Text(tt => tt
                                            .Name(np => np.market)
                                            .Analyzer("standard")
                                        )
                                        .Keyword(k => k
                                            .Name("keyword")
                                            .IgnoreAbove(256)
                                        )
                                    )
                                ).Text(c => c
                                    .Name(np => np.name)
                                    .Analyzer("standard")
                                )
                            )
                        )
                    )
                )
            );

具有以下 POCO 定义

    public class PropertyData
    {
        public string name { get; set; }
        public string city { get; set; }
        public string market { get; set; }
    }

    public class PropertyIndex
    {
        public PropertyData property { get; set; }
    }

    public class OwnerProp
    {
        public string name { get; set; }
        public string market { get; set; }
    }

    public class OwnerIndex
    {
        public OwnerProp owner { get; set; }
    }


像这样尝试通过两个索引进行搜索

 public async Task<object> SearchPropertiesAsync(string searchQuery, List<string> description, int limit = 25, int skip = 1)
        {
            var propertyfilters = new List<Func<QueryContainerDescriptor<object>, QueryContainer>>();
            var ownerFilters = new List<Func<QueryContainerDescriptor<object>, QueryContainer>>();
            if (description.Any())
            {
                propertyfilters.Add(fq => fq.Terms(t => t.Field("property.market.keyword").Terms(description)));
                ownerFilters.Add(fq => fq.Terms(t => t.Field("owner.market.keyword").Terms(description)));
            }

            var searchResponse = await _elasticClient.SearchAsync<object>(s => s
                .Index(Indices.Index(typeof(PropertyIndex)).And(typeof(OwnerIndex)))

                .Query(q => (q
                    .Nested(n => n

                    .Path(Infer.Field<PropertyIndex>(ff => ff.property))

                    .Query(nq => nq

                    .MultiMatch(m => m

                        .Fields(f => f
                            .Field(Infer.Field<PropertyIndex>(ff => ff.property.city))
                            .Field(Infer.Field<PropertyIndex>(ff => ff.property.market))
                            .Field(Infer.Field<PropertyIndex>(ff => ff.property.name))
                        )
                        .Operator(Operator.Or)
                        .Query(searchQuery)
                        .Fuzziness(Fuzziness.Auto)
                    )  && +q.Bool(bq => bq.Filter(propertyfilters))
                        ))
                    ) || (q
                    .Nested(n => n
                    .Path(Infer.Field<OwnerIndex>(ff => ff.mgmt))
                    .Query(nq => nq

                    .MultiMatch(m => m
                        .Fields(f => f
                            .Field(Infer.Field<OwnerIndex>(ff => ff.owner.market))
                            .Field(Infer.Field<OwnerIndex>(ff => ff.owner.name))
                        )
                        .Operator(Operator.Or)
                        .Query(searchQuery)
                        .Fuzziness(Fuzziness.Auto)
                    ) 
                    && +q.Bool(bq => bq.Filter(ownerFilters))
                    ))
                    )
                ).From((skip - 1) * limit)
                    .Size(limit)
            );

            return searchResponse.Documents;
        }

调用 SearchPropertiesAsync 方法 returns 此错误消息(为简洁起见被截断)

         ....
          "index": "owner",
          "caused_by": {
            "type": "illegal_state_exception",
            "reason": "[nested] failed to find nested object under path [property]"
          }

         ....
          "index": "property",
          "caused_by": {
            "type": "illegal_state_exception",
            "reason": "[nested] failed to find nested object under path [owner]"
          }

请注意,它看起来像是在尝试在 property 索引上执行 owner. 的嵌套搜索,并在 owner 索引上执行 property. 的嵌套搜索,但这并不存在.

我觉得这应该是一个非常微不足道的问题,但我使用 ElasticSearch 到现在才 4 天,对它还是很陌生。

我是不是做错了什么,或者是我遗漏了什么。搜索了整个互联网甚至得出了我目前的解决方案。

请注意,当您一次只执行一个索引的嵌套查询时,代码工作正常,但尝试在多个索引上执行是我的问题所在。任何帮助将不胜感激。

我正在使用 ElasticSearch 7.3.2 和 Nest Client 7.3.0。

我不介意降级到可用的较低版本。

显然,根据文档

ignore_unmapped (Optional, boolean) Indicates whether to ignore an unmapped path and not return any documents instead of an error. Defaults to false.

If false, Elasticsearch returns an error if the path is an unmapped field.

You can use this parameter to query multiple indices that may not contain the field path.

因此在每个嵌套查询的查询主体上链接 .IgnoreUnmapped(true) 解决了问题。 以防其他人遇到同样的问题