/ / Elasticsearchのネストが正しく一致しない - elasticsearch、nest

弾性検索ネストが正しくマッチングしない - elasticsearch、nest

ElasticsearchとNest 2.xを使用する

私がする必要があるいくつかの(クレイジーな)ユーザー要件に基づいて検索可能なすべてのフィールドを単一のフィールドにコピーし、小文字にし、スペースを無視します。ユーザーが検索するものを入力すると、それを小文字にして検索文字列として使用するスペースを削除します。

例として: "The quick brown fox" ...弾性検索では検索目的でこれを "thequickbrownfox"にします。

以下の検索は上記の文書と一致するはずです。

  • その
  • テキック
  • t
  • 王冠
  • nf

これが「インデックスの作成方法」です。

var customerSearchIdxDesc = new CreateIndexDescriptor(Constants.ElasticSearch.CustomerSearchIndexName)
.Settings(f =>
f.Analysis(analysis => analysis
.Analyzers(analyzers => analyzers
.Custom(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram, a => a
.Filters("lowercase")
.Tokenizer(Constants.ElasticSearch.TokenizerNames.NoWhitespaceNGram)))
.Tokenizers(tokenizers => tokenizers
.NGram(Constants.ElasticSearch.TokenizerNames.NoWhitespaceNGram, t => t
.MinGram(1)
.MaxGram(500)
.TokenChars(TokenChar.Digit, TokenChar.Letter, TokenChar.Punctuation, TokenChar.Symbol)
)
)
)
)
.Mappings(ms => ms.Map<ServiceModel.DtoTypes.Customer.SearchResult>(m => m
.AutoMap()
.Properties(p => p
.String(n => n.Name(c => c.CustomerName).CopyTo(f =>
{
return new FieldsDescriptor<string>().Field("search");
}).Index(FieldIndexOption.Analyzed).Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.ContactName)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.CustomerName)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.City)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.StateAbbreviation)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.Country)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(c => c.PostalCode)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
.String(n => n.Name(Constants.ElasticSearch.CombinedSearchFieldName)
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.LowercaseNGram))
)
)
);

アナライザで小文字のフィルタを使用していて、空白が省略されているのでTokenCharsを使用していることがわかります(これはうまくいきません)。

これが検索に使用しているものです。

var response = client.Search<DtoTypes.Customer.SearchResult>(s =>
s.From(0)
.Take(Constants.ElasticSearch.MaxResults)
.Query(q => q
.MatchPhrase(mp => mp
.Field(Constants.ElasticSearch.CombinedSearchFieldName)
.Query(query))));

だからここに問題があります:

  • 空白は省略されていないようです(単語に対してのみ一致するように見えます)。
  • 部分一致はサフィックスに対してのみ機能するようです。例えば。 "aby"を検索しても "abyss"と一致しませんが、 "yss"は一致します。
  • 単語を横断して検索すると、 "t working" the quick "..." theq "を検索しても何も一致しません。

回答:

回答№1は0

文字フィルタを追加し、それをアナライザに追加してからEdgeNgramトークナイザを使用することで、これが私の問題を解決すると思います。

var customerSearchIdxDesc = new CreateIndexDescriptor(Constants.ElasticSearch.CustomerSearchIndexName)
.Settings(f =>
f.Analysis(analysis => analysis
.CharFilters(cf => cf
.PatternReplace(Constants.ElasticSearch.FilterNames.RemoveWhitespace, pr => pr
.Pattern(" ")
.Replacement(string.Empty)
)
)
.Analyzers(analyzers => analyzers
.Custom(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer, a => a
.Filters("lowercase")
.CharFilters(Constants.ElasticSearch.FilterNames.RemoveWhitespace)
.Tokenizer(Constants.ElasticSearch.TokenizerNames.DefaultTokenizer)
)
)
.Tokenizers(tokenizers => tokenizers
.EdgeNGram(Constants.ElasticSearch.TokenizerNames.DefaultTokenizer, t => t
.MinGram(1)
.MaxGram(500)
)
)
)
)
.Mappings(ms => ms.Map<ServiceModel.DtoTypes.Customer.SearchResult>(m => m
.AutoMap()
.Properties(p => p
.String(n => n.Name(c => c.CustomerName).CopyTo(f =>
{
return new FieldsDescriptor<string>().Field("search");
}).Index(FieldIndexOption.Analyzed).Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.ContactName)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.CustomerName)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.City)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.StateAbbreviation)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.Country)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(c => c.PostalCode)
.CopyTo(fs => fs.Field(Constants.ElasticSearch.CombinedSearchFieldName))
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
.String(n => n.Name(Constants.ElasticSearch.CombinedSearchFieldName)
.Index(FieldIndexOption.Analyzed)
.Analyzer(Constants.ElasticSearch.AnalyzerNames.DefaultAnalyzer))
)
)
);