Elasticsearch NEST 2 如何正确映射和使用嵌套 类 和批量索引
Elasticsearch NEST 2 How to correctly map and use nested classes and bulk index
我有三个主要问题需要帮助回答。
- 如何正确映射和存储嵌套地图?
- 如何搜索文档的嵌套部分?
- 你如何批量索引?
我正在使用 Nest 版本 2,并且一直在查看可以找到的新文档 Here。该文档对于创建代码的某些部分很有用,但不幸的是没有解释它们是如何组合在一起的。
这是我要映射的 class。
[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)
)
)
));
它确实 return 结果,但我期待
.Term(t => t.PriceList.First().Price, 100)
看起来像
.Term(t => t.Price, 100)
知道是在搜索嵌套的 PriceList class,不是这样吗?
在新版本 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);
return 响应成功,但搜索时没有结果。
如有任何帮助,我们将不胜感激。
更新
在对@Russ advise 进行更多调查后,我认为错误一定是我对带有嵌套对象的 class 的批量索引造成的。
当我使用
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)
)
)
)
);
搜索和 return 结果,但是当我批量索引时这不再有效但是
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 returned 映射根本没有提到嵌套类型,我猜这是问题所在。
我的工作嵌套查询的映射看起来更像这样
{
"my-application2" : {
"mappings" : {
"elasticsearchproduct" : {
"properties" : {
"priceList" : {
"type" : "nested",
"properties" : {
"ID" : {
"type" : "integer"
},
"Price" : {
"type" : "double"
}
}
},
"ID" : {
"type" : "integer"
},
}
}
}
}
}
这具有嵌套类型 returned。我认为当我开始使用 .AutoMap() 时没有 returning 嵌套类型,我使用正确吗?
更新
我已经解决了映射问题。我已将映射代码更改为
var responseMap = client.Map<esProduct>(ms => ms
.AutoMap()
.Properties(ps => ps
.Nested<PriceList>(n => n
.Name(c => c.PriceList)
.AutoMap()
)
)
);
在您开发的同时,I would recommend logging out requests and responses to Elasticsearch 这样您就可以看到使用 NEST 时发送的内容;这将使与主要 Elasticsearch 文档的关联变得更容易,并确保请求和响应的主体符合您的期望(例如,对映射、查询等有用)。
你的映射看起来不错,虽然你可以放弃属性,因为你使用的是流畅的映射;将它们放在那里没有什么坏处,但在这种情况下它们基本上是多余的(esProduct
的类型名称是唯一适用的部分),因为 .Properties()
将覆盖应用的推断映射或基于属性的映射从调用 .AutoMap()
.
在您的索引部分,您 更新 esProduct
然后紧接着,索引 相同的文档;我不确定这里的意图是什么,但是 update 调用对我来说看起来是多余的; index 调用将在 update 之后立即覆盖索引中具有给定 id 的文档(并且在刷新间隔后将在搜索结果中可见). update 上的 .RetryOnConflict(3)
将使用 optimistic concurrency control 执行更新(实际上是 get then index 对集群内的文档进行操作,如果文档的版本在 get 和 index 之间发生变化,将尝试 3 次)。如果您要用 update 替换整个文档,即不是 partial update 那么重试冲突并不是真正必要的(并且按照之前的请注意,您的示例中的 update 调用看起来完全没有必要,因为 index 调用将覆盖索引中具有给定 ID 的文档)。
nested
query looks correct; You specify the path to the nested type and then the query to a field on the nested type will also include the path.I'll update the NEST nested query usage documentation to better demonstrate.
批量调用看起来不错;您可能希望分批发送文件,例如一次批量索引 500 个文档,如果你需要索引很多文档。在一次批量调用中发送多少将取决于许多因素,包括文档大小、分析方式、集群性能,因此需要进行试验以获得适合您情况的良好批量调用。
我会检查以确保您找到了正确的索引,该索引包含您期望的文档数,并找到一个您知道 PriceList.Price
为 100 的文档,然后查看结果为它编制索引。在起床时使用 Sense 可能会更快 运行.
我有三个主要问题需要帮助回答。
- 如何正确映射和存储嵌套地图?
- 如何搜索文档的嵌套部分?
- 你如何批量索引?
我正在使用 Nest 版本 2,并且一直在查看可以找到的新文档 Here。该文档对于创建代码的某些部分很有用,但不幸的是没有解释它们是如何组合在一起的。
这是我要映射的 class。
[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)
)
)
));
它确实 return 结果,但我期待
.Term(t => t.PriceList.First().Price, 100)
看起来像
.Term(t => t.Price, 100)
知道是在搜索嵌套的 PriceList class,不是这样吗?
在新版本 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);
return 响应成功,但搜索时没有结果。
如有任何帮助,我们将不胜感激。
更新
在对@Russ advise 进行更多调查后,我认为错误一定是我对带有嵌套对象的 class 的批量索引造成的。
当我使用
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)
)
)
)
);
搜索和 return 结果,但是当我批量索引时这不再有效但是
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 returned 映射根本没有提到嵌套类型,我猜这是问题所在。
我的工作嵌套查询的映射看起来更像这样
{
"my-application2" : {
"mappings" : {
"elasticsearchproduct" : {
"properties" : {
"priceList" : {
"type" : "nested",
"properties" : {
"ID" : {
"type" : "integer"
},
"Price" : {
"type" : "double"
}
}
},
"ID" : {
"type" : "integer"
},
}
}
}
}
}
这具有嵌套类型 returned。我认为当我开始使用 .AutoMap() 时没有 returning 嵌套类型,我使用正确吗?
更新
我已经解决了映射问题。我已将映射代码更改为
var responseMap = client.Map<esProduct>(ms => ms
.AutoMap()
.Properties(ps => ps
.Nested<PriceList>(n => n
.Name(c => c.PriceList)
.AutoMap()
)
)
);
在您开发的同时,I would recommend logging out requests and responses to Elasticsearch 这样您就可以看到使用 NEST 时发送的内容;这将使与主要 Elasticsearch 文档的关联变得更容易,并确保请求和响应的主体符合您的期望(例如,对映射、查询等有用)。
你的映射看起来不错,虽然你可以放弃属性,因为你使用的是流畅的映射;将它们放在那里没有什么坏处,但在这种情况下它们基本上是多余的(esProduct
的类型名称是唯一适用的部分),因为 .Properties()
将覆盖应用的推断映射或基于属性的映射从调用 .AutoMap()
.
在您的索引部分,您 更新 esProduct
然后紧接着,索引 相同的文档;我不确定这里的意图是什么,但是 update 调用对我来说看起来是多余的; index 调用将在 update 之后立即覆盖索引中具有给定 id 的文档(并且在刷新间隔后将在搜索结果中可见). update 上的 .RetryOnConflict(3)
将使用 optimistic concurrency control 执行更新(实际上是 get then index 对集群内的文档进行操作,如果文档的版本在 get 和 index 之间发生变化,将尝试 3 次)。如果您要用 update 替换整个文档,即不是 partial update 那么重试冲突并不是真正必要的(并且按照之前的请注意,您的示例中的 update 调用看起来完全没有必要,因为 index 调用将覆盖索引中具有给定 ID 的文档)。
nested
query looks correct; You specify the path to the nested type and then the query to a field on the nested type will also include the path.I'll update the NEST nested query usage documentation to better demonstrate.
批量调用看起来不错;您可能希望分批发送文件,例如一次批量索引 500 个文档,如果你需要索引很多文档。在一次批量调用中发送多少将取决于许多因素,包括文档大小、分析方式、集群性能,因此需要进行试验以获得适合您情况的良好批量调用。
我会检查以确保您找到了正确的索引,该索引包含您期望的文档数,并找到一个您知道 PriceList.Price
为 100 的文档,然后查看结果为它编制索引。在起床时使用 Sense 可能会更快 运行.