【问题标题】:Elasticsearch NEST 2 How to correctly map and use nested classes and bulk indexElasticsearch NEST 2 如何正确映射和使用嵌套类和批量索引
【发布时间】:2016-03-31 10:14:19
【问题描述】:

我有三个主要问题需要帮助回答。

  1. 如何正确映射和存储嵌套地图?
  2. 如何搜索文档的嵌套部分?
  3. 如何批量索引?

我使用的是 Nest 版本 2,并且一直在查看可以在 Here 找到的新文档。该文档在创建代码的某些部分时很有用,但遗憾的是没有解释它们是如何组合在一起的。

这是我要映射的类。

[ElasticsearchType(Name = "elasticsearchproduct", IdProperty = "ID")]
public class esProduct
{
    public int ID { get; set; }
    [Nested]
    public List<PriceList> PriceList { get; set; }
}

[ElasticsearchType(Name = "PriceList")]
public class PriceList
{
    public int ID { get; set; }
    public decimal Price { get; set; }
}

还有我的映射代码

var node = new Uri(HOST);
        var settings = new ConnectionSettings(node).DefaultIndex("my-application");

        var client = new ElasticClient(settings);
        var map = new CreateIndexDescriptor("my-application")
                        .Mappings(ms => ms
                            .Map<esProduct>(m => m
                                .AutoMap()
                                .Properties(ps => ps
                                    .Nested<PriceList>(n => n
                                        .Name(c => c.PriceList)
                                        .AutoMap()
                                    )
                                )
                            )
                        );

        var response = client.Index(map);

这是我得到的回复:

Valid NEST response built from a succesful low level call on POST: /my-application/createindexdescriptor

所以这似乎有效。下一个索引。

foreach (DataRow dr in ProductTest.Tables[0].Rows)
{
    int id = Convert.ToInt32(dr["ID"].ToString());
    List<PriceList> PriceList = new List<PriceList>();
    DataRow[] resultPrice = ProductPriceTest.Tables[0].Select("ID = " + id);

    foreach (DataRow drPrice in resultPrice)
    {
        PriceList.Add(new PriceList
        {
            ID = Convert.ToInt32(drPrice["ID"].ToString()),
            Price = Convert.ToDecimal(drPrice["Price"].ToString())    
        }

        esProduct product = new esProduct
        {
            ProductDetailID = id,
            PriceList = PriceList
        };

       var updateResponse = client.Update<esProduct>(DocumentPath<esProduct>.Id(id), descriptor => descriptor
                                    .Doc(product)
                                    .RetryOnConflict(3)
                                    .Refresh()
                );

       var index = client.Index(product);
    }
}

这似乎再次起作用,但是当我开始搜索时,它似乎确实按预期工作。

var searchResults = client.Search<esProduct>(s => s
                            .From(0)
                            .Size(10)
                                .Query(q => q
                                       .Nested(n => n
                                           .Path(p => p.PriceList)
                                            .Query(qq => qq
                                                .Term(t => t.PriceList.First().Price, 100)
                                                )
                                            )
                                      ));

它确实返回结果,但我期待

.Term(t => t.PriceList.First().Price, 100)

看起来像移动

.Term(t => t.Price, 100)

并且知道这是在搜索嵌套的 PriceList 类,不是这样吗?

在新版本 2 文档中,我找不到批量索引部分。我尝试使用此代码

var descriptor = new BulkDescriptor();

***Inside foreach loop***

descriptor.Index<esProduct>(op => op
                            .Document(product)
                            .Id(id)
                            );
***Outside foreach loop***

var result = client.Bulk(descriptor);

它确实返回了成功响应,但是当我搜索时我没有得到任何结果。

任何帮助将不胜感激。

更新

在对@Russ 建议进行更多调查后,我认为错误一定是我对具有嵌套对象的类的批量索引。

当我使用时

var index = client.Index(product);

索引我可以使用的每个产品

var searchResults = client.Search<esProduct>(s => s
                    .From(0)
                    .Size(10)
                        .Query(q => q
                        .Nested(n => n
                            .Path(p => p.PriceList)
                            .Query(qq => qq
                                    .Term(t => t.PriceList.First().Price, 100)
                                )
                            )
                        )
                     );

搜索并返回结果,但是当我批量索引时,这不再有效,而是

var searchResults = client.Search<esProduct>(s => s
                    .From(0)
                    .Size(10)
                    .Query(q => q
                            .Term(t => t.PriceList.First().Price, 100)
                          )
                     );

会起作用,代码 b 不适用于单个索引方法。有谁知道为什么会这样?

更新 2

@Russ 建议我查看映射。

我用来索引的代码是

var map = new CreateIndexDescriptor(defaultIndex)
                        .Mappings(ms => ms
                            .Map<esProduct>(m => m
                                .AutoMap()
                                .Properties(ps => ps
                                    .Nested<PriceList>(n => n
                                        .Name(c => c.PriceList)
                                        .AutoMap()
                                    )
                                )
                            )
                        );

        var response = client.Index(map);

发布的内容

http://HOST/fresh-application2/createindexdescriptor {"mappings":{"elasticsearchproduct":{"properties":{"ID":{"type":"integer"},"priceList":{"type":"nested","properties":{"ID":{"type":"integer"},"Price":{"type":"double"}}}}}}}

我正在打电话给http://HOST/fresh-application2/_all/_mapping?pretty

{
  "fresh-application2" : {
    "mappings" : {
      "createindexdescriptor" : {
        "properties" : {
          "mappings" : {
            "properties" : {
              "elasticsearchproduct" : {
                "properties" : {
                  "properties" : {
                    "properties" : {
                      "priceList" : {
                        "properties" : {
                          "properties" : {
                            "properties" : {
                              "ID" : {
                                "properties" : {
                                  "type" : {
                                    "type" : "string"
                                  }
                                }
                              },
                              "Price" : {
                                "properties" : {
                                  "type" : {
                                    "type" : "string"
                                  }
                                }
                              }
                            }
                          },
                          "type" : {
                            "type" : "string"
                          }
                        }
                      },
                      "ID" : {
                        "properties" : {
                          "type" : {
                            "type" : "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

fresh-application2 返回的映射根本没有提到嵌套类型,我猜这是问题所在。

我的工作嵌套查询的映射看起来更像这样

{
  "my-application2" : {
    "mappings" : {
      "elasticsearchproduct" : {
        "properties" : {
          "priceList" : {
            "type" : "nested",
            "properties" : {
              "ID" : {
                "type" : "integer"
              },
              "Price" : {
                "type" : "double"
              }
            }
          },
          "ID" : {
            "type" : "integer"
          },
        }
      }
    }
  }
}

这具有返回的嵌套类型。我认为当我开始使用 .AutoMap() 时,没有返回嵌套类型的那个,我是否正确使用它?

更新

我已经解决了我的映射问题。我已将映射代码更改为

var responseMap = client.Map<esProduct>(ms => ms
                            .AutoMap()
                            .Properties(ps => ps
                                .Nested<PriceList>(n => n
                                    .Name(c => c.PriceList)
                                .AutoMap()
                                )
                            )
                        );

【问题讨论】:

  • 是的,NEST 文档很糟糕。它只给出片段,而不是完整的例子。 NEST 也完全没有必要——它只是对你隐藏了 REST API,如果你正在做任何不重要的事情(即:有人会实际使用的项目),那么它的麻烦多于它的价值。只需直接使用 REST API,您就可以 100% 地完成 elasticsearch 让您做的事情。 NEST 是另一个无用的抽象层

标签: elasticsearch nested nest


【解决方案1】:

在您开发的同时,I would recommend logging out requests and responses to Elasticsearch 这样您就可以看到使用 NEST 时发送的内容;这将更容易与主要的 Elasticsearch 文档相关联,并确保请求和响应的主体符合您的期望(例如,对映射、查询等有用)。

您的映射看起来不错,尽管您可以放弃属性,因为您使用的是流畅的映射;将它们放在那里并没有什么坏处,但在这种情况下它们基本上是多余的(esProduct 的类型名称是唯一适用的部分),因为.Properties() 将覆盖通过调用@987654330 应用的推断或基于属性的映射@。

在您的索引部分,您更新 esProduct,然后立即再次索引同一文档;我不确定这里的意图是什么,但 update 调用对我来说似乎是多余的; index 调用将在 update 之后立即覆盖索引中具有给定 id 的文档(并且在刷新间隔后将在搜索结果中可见)。 update 上的.RetryOnConflict(3) 将使用optimistic concurrency control 执行更新(这实际上是对内部文档的get then index 操作如果文档的版本在 getindex 之间发生变化,它将尝试 3 次)。如果您用 update 替换整个文档,即不是 partial update,那么重试冲突并不是真正必要的(根据前面的说明,您的示例中的 update 调用看起来完全没有必要,因为 index 调用将覆盖索引中具有给定 id 的文档)。

nested query 看起来正确;您指定嵌套类型的路径,然后对嵌套类型上的字段的查询也将包含该路径。I'll update the NEST nested query usage documentation to better demonstrate

批量调用看起来不错;您可能希望分批发送文件,例如如果您需要索引大量文档,则一次批量索引 500 个文档。在一次批量调用中发送多少将取决于许多因素,包括文档大小、分析方式、集群性能,因此需要进行试验以获得适合您情况的批量调用。

我会检查以确保您点击了正确的索引,该索引包含您期望的文档数,并找到您知道的 PriceList.Price 为 100 的文档,并查看为它编入索引的内容.在您开始跑步时使用Sense 可能会更快。

【讨论】:

  • 谢谢@Russ,您为我解决了很多问题。如果您可以看一下,我已经更新了我的任务并提供了更多信息。
  • @BenClose 当您使用elastic.co/guide/en/elasticsearch/reference/current/… 获取映射时,该映射在索引中的外观如何?它有嵌套映射吗?批量请求是什么样的?您可以添加一个捕获请求的小示例吗?
  • 查看映射是一个问题,它没有作为嵌套的 PriceList 返回,即使它是在地图 POST 中设置的。有任何想法吗?我在问题中添加了更多信息。
  • 感谢您的所有帮助,我已通过使用 client.Map 方法而不是似乎嵌套不正确的 CreateIndexDescriptor(defaultIndex).Mappings 方法解决了我的问题。
  • @BenClose 您使用的是哪个版本的 NEST,以及针对哪个版本的 Elasticsearch?如果你认为这是一个错误,你介意在github.com/elastic/elasticsearch-net/issues 上用一个简短的例子打开一个问题吗?您确定在调用CreateIndexDecriptor() 之前没有使用不正确 映射创建索引吗? (如果索引已经存在,create 调用不会改变映射)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 2016-03-27
相关资源
最近更新 更多