我无法弄清楚如何索引和搜索嵌套对象。
我希望能够搜索嵌套对象并返回父母 - 只有父母,没有备注列表,但如果可能的话,我希望从返回的备注中突出显示。
我的模型:
[DataContract]
[ElasticsearchType(IdProperty = "CustomerId", Name = "CustomerSearchResult")]
public class SearchResult
{
[DataMember]
[String(Index = FieldIndexOption.NotAnalyzed)]
public int CustomerId { get; set; }
...
[Nested]
[DataMember]
public List<RemarkForSearch> Remarks { get; set; }
}
[ElasticsearchType(IdProperty = "RemarkId", Name = "RemarkForSearch")]
public class RemarkForSearch
{
[DataMember]
public int RemarkId { get; set; }
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public string RemarkText { get; set; }
}
索引创建:
var customerSearchIdxDesc = new CreateIndexDescriptor(Constants.ElasticSearch.CustomerSearchIndexName)
.Settings(f =>
f.Analysis(analysis => analysis
.CharFilters(cf => cf
.PatternReplace(Constants.ElasticSearch.FilterNames.RemoveNonAlphaNumeric, pr => pr
.Pattern(@"[^a-zA-Z\d]") // match all non alpha numeric
.Replacement(string.Empty)
)
)
.TokenFilters(tf => tf
.NGram(Constants.ElasticSearch.FilterNames.NGramFilter, fs => fs
.MinGram(1)
.MaxGram(20)
)
)
.Analyzers(analyzers => analyzers
.Custom(Constants.ElasticSearch.AnalyzerNames.NGramAnalyzer, a => a
.Filters("lowercase", "asciifolding", Constants.ElasticSearch.FilterNames.NGramFilter)
.Tokenizer(Constants.ElasticSearch.TokenizerNames.WhitespaceTokenizer)
)
.Custom(Constants.ElasticSearch.AnalyzerNames.WhitespaceAnalyzer, a => a
.Filters("lowercase", "asciifolding")
.Tokenizer(Constants.ElasticSearch.TokenizerNames.WhitespaceTokenizer)
)
.Custom(Constants.ElasticSearch.AnalyzerNames.FuzzyAnalyzer, a => a
.Filters("lowercase", "asciifolding")
//.CharFilters(Constants.ElasticSearch.FilterNames.RemoveNonAlphaNumeric)
.Tokenizer(Constants.ElasticSearch.TokenizerNames.NGramTokenizer)
)
)
.Tokenizers(tokenizers => tokenizers
.NGram(Constants.ElasticSearch.TokenizerNames.NGramTokenizer, t => t
.MinGram(1)
.MaxGram(20)
//.TokenChars(TokenChar.Letter, TokenChar.Digit)
)
.Whitespace(Constants.ElasticSearch.TokenizerNames.WhitespaceTokenizer)
)
)
)
.Mappings(ms => ms
.Map<ServiceModel.DtoTypes.Customer.SearchResult>(m => m
.AutoMap()
.AllField(s => s
.Analyzer(Constants.ElasticSearch.AnalyzerNames.NGramAnalyzer)
.SearchAnalyzer(Constants.ElasticSearch.AnalyzerNames.WhitespaceAnalyzer)
)
.Properties(p => p
.String(n => n
.Name(c => c.ContactName)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(c => c.CustomerName)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(c => c.City)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(c => c.StateAbbreviation)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(c => c.PostalCode)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(c => c.Country)
.Index(FieldIndexOption.NotAnalyzed)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.Number(n => n
.Name(c => c.AverageMonthlySales)
.Type(NumberType.Double)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
)
.String(n => n
.Name(Constants.ElasticSearch.CombinedSearchFieldName)
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.FuzzyAnalyzer)
.SearchAnalyzer(Constants.ElasticSearch.AnalyzerNames.FuzzyAnalyzer)
)
.Nested<ServiceModel.DtoTypes.Customer.RemarkForSearch>(s => s
.Name(n => n.Remarks)
.AutoMap()
)
)
)
);
var response = client.CreateIndex(customerSearchIdxDesc);
加载索引:
var searchResults = Db.SqlList<DtoTypes.Customer.SearchResult>("EXEC [Customer].[RetrieveAllForSearch]");
var remarkResults = Db.SqlList<DtoTypes.Customer.RemarkForSearch>("EXEC [Customer].[RetrieveAllSearchableRemarks]");
foreach(var i in searchResults)
{
i.Remarks = remarkResults.Where(m => m.CustomerId == i.CustomerId).ToList();
}
var settings = new ConnectionSettings(Constants.ElasticSearch.Node);
var client = new ElasticClient(settings);
// Flush the index
var flushResponse = client.Flush(Constants.ElasticSearch.CustomerSearchIndexName);
// Refresh index
var indexResponse = client.IndexMany(searchResults, Constants.ElasticSearch.CustomerSearchIndexName);
查询索引:
var searchDescriptor = new SearchDescriptor<DtoTypes.Customer.SearchResult>()
.From(0)
.Take(Constants.ElasticSearch.MaxResults)
.Query(q => q
.Nested(c => c
.Path(p => p.Remarks)
.Query(nq => nq
.Match(m => m
.Query(query)
.Field("remarks.remarktext")
)
)
)
);
response = client.Search<DtoTypes.Customer.SearchResult>(searchDescriptor);
我不知道我是否正确地批量加载索引,以及它是否足够聪明,知道 Remarks 属性是一个嵌套属性并加载它们。
搜索没有错误,但我没有得到任何结果。
搜索查询正在生成这个 json,据我所知,这是可以的:
{
"from": 0,
"size": 100,
"query": {
"nested": {
"query": {
"match": {
"remarks.remarktext": {
"query": "test"
}
}
},
"path": "remarks"
}
}
}
使用查询字符串http://127.0.0.1:9200/customersearch/_search查看 json 时,我确实看到了备注数据