1)首先,有一个索引是一个好主意,在我的情况下是帐户,并且产品是嵌套对象,但是在这里每次我要更新/添加新产品时,我都必须重新索引(更新)整个帐户文件?
通常建议每个索引具有一种类型,在Elasticsearch
6.0+中,每个索引只能具有一种类型。如果将产品表示为帐户上的嵌套对象,则向帐户中添加新产品将需要更新整个文档(
在您的应用程序代码中或在Elasticsearch中 )。
2)我的第二个问题是:我想具有搜索功能,因此,如果用户通过在文本框中键入内容进行搜索,则我希望同时获得“帐户”和“产品”的最佳匹配(此处,我将针对产品的名称和说明以及帐户名称和说明,然后获得最佳匹配):
您可以搜索多个索引,查看协变搜索结果的文档;它显示了从一个索引返回多种不同类型的示例(此示例将更新为6.0!),但是可以跨多个索引执行此操作。这是一个例子:
private static void Main(){ var settings = new ConnectionSettings(new Uri("http://localhost:9200")) .InferMappingFor<AccountType>(i => i .IndexName("account") ) .InferMappingFor<ProductType>(i => i .IndexName("product") ) // useful for development, to make the request/response bytes // available on the response .DisableDirectStreaming() // indented JSON in requests/responses .PrettyJson() // log out all requests/responses .onRequestCompleted(callDetails => { if (callDetails.RequestBodyInBytes != null) { Console.WriteLine( $"{callDetails.HttpMethod} {callDetails.Uri} n" + $"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}"); } else { Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}"); } Console.WriteLine(); if (callDetails.ResponseBodyInBytes != null) { Console.WriteLine($"Status: {callDetails.HttpStatusCode}n" + $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}n" + $"{new string('-', 30)}n"); } else { Console.WriteLine($"Status: {callDetails.HttpStatusCode}n" + $"{new string('-', 30)}n"); } }); var client = new ElasticClient(settings); if (client.IndexExists("account").Exists) client.DeleteIndex("account"); client.CreateIndex("account", i => i .Settings(s => s .NumberOfShards(2) .NumberOfReplicas(0) ) .Mappings(m => m .Map<AccountType>(map => map .AutoMap() .Properties(p => p .Text(c => c .Name(n => n.Name) .Analyzer("standard") ) .Text(c => c .Name(n => n.Description) .Analyzer("standard") ) ) ) ) ); if (client.IndexExists("product").Exists) client.DeleteIndex("product"); client.CreateIndex("product", i => i .Settings(s => s .NumberOfShards(2) .NumberOfReplicas(0) ) .Mappings(m => m .Map<ProductType>(map => map .AutoMap() .Properties(p => p .Text(c => c .Name(n => n.Title) .Analyzer("standard") ) .Text(c => c .Name(n => n.Description) .Analyzer("standard") ) ) ) ) ); client.IndexMany(new[] { new AccountType { Name = "Name 1", Description = "Description 1" }, new AccountType { Name = "Name 2", Description = "Description 2" }, new AccountType { Name = "Name 3", Description = "Description 3" }, new AccountType { Name = "Name 4", Description = "Description 4" }, }); client.IndexMany(new[] { new ProductType { Title = "Title 1", Description = "Description 1" }, new ProductType { Title = "Title 2", Description = "Description 2" }, new ProductType { Title = "Title 3", Description = "Description 3" }, new ProductType { Title = "Title 4", Description = "Description 4" }, }); var indices = Indices.Index(typeof(ProductType)).And(typeof(AccountType)); client.Refresh(indices); var searchResponse = client.Search<object>(s => s .Index(indices) .Type(Types.Type(typeof(ProductType), typeof(AccountType))) .Query(q => (q .MultiMatch(m => m .Fields(f => f .Field(Infer.Field<ProductType>(ff => ff.Title, 1.5)) .Field(Infer.Field<ProductType>(ff => ff.Description, 0.8)) ) .Operator(Operator.Or) .Query("Title 1") ) && +q .Term("_index", "product")) || (q .MultiMatch(m => m .Fields(f => f .Field(Infer.Field<AccountType>(ff => ff.Name, 3)) .Field(Infer.Field<AccountType>(ff => ff.Description, 0.3)) ) .Operator(Operator.Or) .Query("Name 4") ) && +q .Term("_index", "account")) ) ); foreach (var document in searchResponse.documents) Console.WriteLine($"document is a {document.GetType().Name}");}public class ProductType{ public string Title { get; set; } public string Description { get; set; }}public class AccountType{ public string Name { get; set; } public string Description { get; set; }}结果是
document is a AccountTypedocument is a ProductTypedocument is a AccountTypedocument is a ProductTypedocument is a AccountTypedocument is a AccountTypedocument is a ProductTypedocument is a ProductType
这里有很多事情,所以让我解释一下。搜索请求JSON如下所示:
POST http://localhost:9200/product%2Caccount/producttype%2Caccounttype/_search?pretty=true { "query": { "bool": { "should": [ { "bool": { "must": [ { "multi_match": { "query": "Title 1", "operator": "or", "fields": [ "title^1.5", "description^0.8" ] } } ], "filter": [ { "term": { "_index": { "value": "product" } } } ] } }, { "bool": { "must": [ { "multi_match": { "query": "Name 4", "operator": "or", "fields": [ "name^3", "description^0.3" ] } } ], "filter": [ { "term": { "_index": { "value": "account" } } } ] } } ] } }}该搜索是在
product和
account索引之间,在
producttype和
accounttype类型之间执行的。在
title和
description字段上执行multi_match查询,并将其与使用布尔查询的术语查询结合,以将查询约束到
product索引。术语查询位于过滤器子句中,因为不应为该术语查询计算相关性得分。此布尔查询与另一个布尔查询结合在一起,该布尔查询对
name和
description字段执行multi_match查询,并与术语查询组合以将查询约束到
account索引。这两个布尔查询使用should子句合并,因为其中一个布尔查询或另一个布尔布尔查询需要匹配。
object作为通用的参数类型的
Search<T>()方法调用,因为
ProductType和
AccountType不共享一个公共基类(除了
object!),其产生的文档集合可以分型。但是,从结果中我们可以看到,NEST实际上已反序列化了类型
producttype为的实例的
ProductType文档和类型
accounttype为的实例的文档
AccountType。
该查询使用运算符重载来更简洁地组合查询。



