【问题标题】:Search ElasticSearch / Nest - Address Suggestion Api with Category Filter搜索 ElasticSearch / Nest - 带有类别过滤器的地址建议 API
【发布时间】:2018-09-10 18:19:42
【问题描述】:

调用我的 Rest API 的用户必须能够指定地点类型,然后获得地名建议。

地点类型必须准确,而地点名称搜索会充分利用 elaticsearch 搜索的所有潜力。

我正在使用 NEST(最新的 nuget 版本)和 Elastic 6.4。

我的 Api 有 2 个参数: 1.查询:搜索文本搜索 2. placetypes:数组,用于定义建议中所需的文档“类别”

带有查询参数的地名建议效果很好, 但是我不知道如何添加placetype的条件。

嵌套映射:

return map
  .Dynamic(false)
  .Properties(props => props
    .Keyword(n => n
      .Name(p => p.Id))
    .Text(n => n
      .Name(p => p.PlaceType))
    .Completion(n => n
      .Name(p => p.PlaceName)
      .Analyzer("autocompletion_indexation"))
    .Completion(n => n
      .Name(p => p.Address)
      .Analyzer("autocompletion_indexation"))
    .GeoPoint(loc =>
      {
      loc.Name(location => location.Coordinates);
      return loc;
      }));

巢分析描述符:

return analysis
    .CharFilters(c => c
        .HtmlStrip("html_strip")
    )
    .Tokenizers(t => t
        .EdgeNGram("custom_ngram", descriptor =>
            {
            descriptor.MinGram(2);
            descriptor.MaxGram(10);
            descriptor.TokenChars(new List<TokenChar> { TokenChar.Letter, TokenChar.Digit });
            return descriptor;
            }
        ))
    .TokenFilters(tf => tf
        .Lowercase("lowercase")
        .WordDelimiter("word_delimiter", wd =>wd
        .SplitOnNumerics()
        .SplitOnCaseChange()
    )
    .AsciiFolding("asciifolding", af => af
        .PreserveOriginal(false)
    )
    .Elision("elision", e => e
        .Articles("l", "d", "o")
    )
    .Synonym("address_synonym", sy => sy
        .Synonyms(GetSynonyms())
        .Tokenizer("standard")
        .Tokenizer("whitespace")
    )
    .Stop("french_stop", fs => fs
        .StopWords("_french_"))
    .Stemmer("french_stemmer", fs => fs
    .Language("light_french")
)
)
    .Analyzers(an => an
        .Custom("autocompletion_indexation", c => c
        .Tokenizer("custom_ngram")
        .Tokenizer("standard")
        .Tokenizer("whitespace")
        .CharFilters("html_strip")
        .Filters("address_synonym",
        "lowercase",
        "asciifolding",
        "elision",
        "word_delimiter",
        "stop",
        "french_stemmer",
        "french_stop")
));    

建议/搜索功能:

public Task<List<Place>> SuggestDocuments(CancellationToken cancellationToken, string query, params string[] placeTypes)
{
var search = new SearchDescriptor<Place>()
    .From(0)
    .Size(10)
    .Index(PlaceDataService.DefaultPostalAddressIndexName)
    .Query(q => q
        .MultiMatch(mm => mm
        .Query(query)
        .Fuzziness(Fuzziness.Auto)
        .Fields(fields => fields
            .Field(f => f.PlaceName)
            )));

var searchResults = _elasticClient.SearchAsync<Place>(search, cancellationToken);
return Task.Run(() => searchResults.Result.Documents.ToList(), cancellationToken);
}

【问题讨论】:

    标签: c# elasticsearch nest search-suggestion


    【解决方案1】:

    您可以将multi_match 查询与terms 查询结合起来,通过将它们包装在bool 查询中来实现此目的

    var query = "this is the place name";
    var places = new [] { "Place 1", "Place 2" };
    
    var search = new SearchDescriptor<Place>()
        .From(0)
        .Size(10)
        .Index("index")
        .Query(q => q
            .MultiMatch(mm => mm
                .Query(query)
                .Fuzziness(Fuzziness.Auto)
                .Fields(fields => fields
                    .Field(f => f.PlaceName)
                )
            ) && +q
            .Terms(t => t
                .Field(f => f.PlaceType)
                .Terms(places)
            )
        );
    
    var searchResults = await _elasticClient.SearchAsync<Place>(search, cancellationToken);
    

    以上使用运算符重载进行查询,您可以在Writing Bool queries docs 中了解更多信息。以上产生以下请求

    {
      "from": 0,
      "size": 10,
      "query": {
        "bool": {
          "must": [
            {
              "multi_match": {
                "query": "this is the place name",
                "fuzziness": "AUTO",
                "fields": [
                  "placeName"
                ]
              }
            }
          ],
          "filter": [
            {
              "terms": {
                "placeType": [
                  "Place 1",
                  "Place 2"
                ]
              }
            }
          ]
        }
      }
    }
    

    请注意,terms 查询将对术语进行OR,因此至少需要匹配一个。如果所有输入都需要匹配,可以和多个term一起查询。

    您的映射和分析有些地方看起来不太正确

    1. PlaceName 映射为 completion datatype,但用于 multi_match 搜索查询,而不是 suggest 搜索。对于这种情况,我本来希望它被映射为 text 数据类型。
    2. 如果PlaceType 字段需要按原样匹配完全,我希望它们被映射为keyword datatype
    3. html_strip char 过滤器是内置的,因此不需要重新指定,除非您需要自定义它的工作方式,例如escaped_tags。 lowercase 令牌过滤器也是如此。
    4. "autocompletion_indexation" 自定义分析器只能有一个分词器,因此最后分配的胜出("whitespace" 分词器)。查看writing analyzers docs。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      • 2015-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多