2017-08-09 163 views
2

我想在文本的下方列表中搜索单词蓝色春数据弹性搜索通配符搜索

“BlueSaphire”,“Bluo”,“ALUE”,“蓝”,“蓝” , “蓝”, “蓝黑色”, “Bluo”, “萨费尔蓝色”, “黑”, “绿色”, “布卢”, “Saphireblue”

SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices("color") 
        .withQuery(matchQuery("colorDescriptionCode", "blue") 
        .fuzziness(Fuzziness.ONE) 
       ) 
        .build(); 

这工作得很好,并且搜索结果将以下记录与分数一起返回

alue 2.8718023 
Bluo 1.7804208 
Bluo 1.7804208 
BLUE 1.2270637 
blue 1.2270637 
Blue 1.2270637 
Blue Black 1.1082436 
Saphire Blue 0.7669148 

但我不能使通配符工作。 “SaphireBlue”和“BlueSaphire”也有望成为结果的一部分

我试过下面的设置,但它不起作用。

SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices("color") 
         .withQuery(matchQuery("colorDescriptionCode", "(.*?)blue") 
         .fuzziness(Fuzziness.ONE) 
        ) 
         .build(); 

在堆栈溢出中,我观察到指定分析通配符的解决方案。

QueryBuilder queryBuilder = boolQuery().should(
       queryString("blue").analyzeWildcard(true) 
         .field("colorDescriptionCode", 2.0f); 

我没有找到queryString静态方法。我正在使用spring-data-elasticsearch 2.0.0.RELEASE。

让我知道,这样蓝色也将在搜索返回的结果

+0

您的映射和集群设置只能帮助正则表达式 – user3775217

+0

您能否详细说明您的评论?你的意思是在弹性搜索中配置同义词吗? – lives

+0

我不知道,那是在那个时候,你不能再以这样一种违法的方式再问我,直到我得到我非常体面的要求,或者可能在野外飞行时想到我可能已经学会的东西。谢谢 – user3775217

回答

0

我不能在一个查询实现模糊性和Wilcard搜索包含所有的话,我如何能够指定的外卡。

这是我可以得到的最接近的解决方案。我必须激发两个不同的查询并手动合并结果。

@Query("{\"wildcard\" : {\"colorDescriptionCode\" : \"?0\" }}") 
    Page<ColorDescription> findByWildCard(String colorDescriptionCode, Pageable pageable); 

    @Query("{\"match\": { \"colorDescriptionCode\": { \"query\":  \"?0\", \"fuzziness\": 1 }}}") 
    Page<ColorDescription> findByFuzzy(String colorDescriptionCode, Pageable pageable); 
0

我知道工作的例子总是比理论好,但我仍然想先讲一点理论。 Elasticsearch的核心是Lucene。所以在将文档写入Lucene索引之前,他会经历分析阶段。分析阶段可分为3部分:

  1. 字符过滤;
  2. 标记化;
  3. 令牌过滤

在第一阶段中,我们可以扔掉不必要的字符,例如,HTML标签。有关字符过滤器的更多信息,请参阅official site。 下一阶段更有趣。在这里,我们将输入文本分割为记号,稍后将用于搜索。一些非常有用的tokenizers

  • 标准分词器。它是默认使用的。标记器实现Unicode文本分段算法。在实践中,您可以使用它将文本分割成单词并将这些单词用作记号。
  • n-gram标记器。如果你想要搜索单词的一部分,这就是你需要的。该标记器将文本分割为n个项目的连续序列。例如,文本“例如”将被分割为这个标记序列"fo", "or", "r ", " e", "ex", "for", "or ex"等.n-gram的长度是可变的,并且可以由min_gram和max_gram params来配置。
  • edge n-gram tokenizer。与n-gram标记器相同,除了一件事情 - 该标记器不增加偏移量。例如,文本“例如”将被分割为这个标记序列"fo", "for", "for ", "for e", "for ex", "for exa"等。 关于标记器的更多信息可以在官方网站上找到。不幸的是,由于声誉低下,我无法发布更多链接。

下一个阶段也是该死的有趣。在我们将文本分成标记之后,我们可以用这个做很多有趣的事情。我再次给令牌过滤器的一些非常有用的例子:

  • 小写过滤。在大多数情况下,我们希望得到不区分大小写的搜索,所以最好将令牌标记为小写。
  • 词干分析过滤器。当我们与自然语言达成协议时,我们遇到很多问题。其中一个问题是一个词可以有多种形式。 Stemmer过滤器可以帮助我们获得单词的根形式。
  • 模糊滤波器。另一个问题是用户经常犯错。此过滤器添加包含可能的拼写错误的标记。

如果你有兴趣看分析的结果,你可以使用这个_termvectors端点

curl [ELASTIC_URL]:9200/[INDEX_NAME]/[TYPE_NAME]/[DOCUMENT_ID]/_termvectors?pretty 

现在说说查询。查询分为2个大组。这些组有两个显着差异:

  1. 请求是否会通过分析阶段;
  2. 是否要求有一个确切的答案(是或否)

例子是匹配查询和搜索项查询。第一个将通过分析阶段,第二个不会。第一个不会给我们一个具体的答案(但给我们一个分数),第二个会。为文档创建映射时,我们可以分别指定分析器的索引和搜索分析器的每个字段。

现在有关弹簧数据elasticsearch的信息。这里讲一些具体的例子很有意义。假设我们有一个带有标题字段的文档,我们想要搜索该字段的信息。首先,创建一个包含elasticsearch设置的文件。

{ 
"analysis": { 
    "analyzer": { 
     "ngram_analyzer": { 
      "tokenizer": "ngram_tokenizer", 
      "filter": [ 
       "lowercase" 
      ] 
     }, 
     "edge_ngram_analyzer": { 
      "tokenizer": "edge_ngram_tokenizer", 
      "filter": [ 
       "lowercase" 
      ] 
     }, 
     "english_analyzer": { 
      "tokenizer": "standard", 
      "filter": [ 
       "lowercase", 
       "english_stop", 
       "unique", 
       "english_possessive_stemmer", 
       "english_stemmer" 
      ] 
     "keyword_analyzer": { 
      "tokenizer": "keyword", 
      "filter": ["lowercase"] 
     } 

    }, 
    "tokenizer": { 
     "ngram_tokenizer": { 
      "type": "ngram", 
      "min_gram": 2, 
      "max_gram": 20 
     }, 
     "edge_ngram_tokenizer": { 
      "type": "edge_ngram", 
      "min_gram": 2, 
      "max_gram": 20 
     } 
    }, 
    "filter": { 
     "english_stop": { 
      "type": "stop", 
      "stopwords": "_english_" 
     }, 
    "english_stemmer": { 
     "type": "stemmer", 
     "language": "english" 
    }, 
    "english_possessive_stemmer": { 
     "type": "stemmer", 
     "language": "possessive_english" 
    } 
}  
} 

您可以将此设置保存到您的资源文件夹中。现在让我们看看我们的文档类

@Document(indexName = "document", type = "document") 
@Setting(settingPath = "document_index_setting.json") 
public class Document { 

    @Id 
    private String id; 

    @MultiField(
     mainField = @Field(type = FieldType.String, 
          index = not_analyzed), 
     otherFields = { 
       @InnerField(suffix = "edge_ngram", 
         type = FieldType.String, 
         indexAnalyzer = "edge_ngram_analyzer", 
         searchAnalyzer = "keyword_analyzer"), 
       @InnerField(suffix = "ngram", 
         type = FieldType.String, 
         indexAnalyzer = "ngram_analyzer"), 
         searchAnalyzer = "keyword_analyzer"), 
       @InnerField(suffix = "english", 
         type = FieldType.String, 
         indexAnalyzer = "english_analyzer") 
     } 
    ) 
    private String title; 

    // getters and setters omitted 

} 

所以在这里场冠军,三个内场:

  • title.edge_ngram由边缘正克用关键词搜索分析搜索。我们需要这个,因为我们不需要将我们的查询分割成边缘n元组;
  • title.ngram用于n-grams搜索;
  • title.english用于搜索与自然语言的细微差别 和主要字段标题。我们不分析这个,因为有时候我们想按这个字段排序。 让我们用简单的多匹配查询通过所有这些领域的搜索:
String searchQuery = "blablabla"; 
MultiMatchQueryBuilder queryBuilder = multiMatchQuery(searchQuery) 
    .field("title.edge_ngram", 2) 
    .field("title.ngram") 
    .field("title.english"); 
NativeSearchQueryBuilder searchBuilder = new NativeSearchQueryBuilder() 
    .withIndices("document") 
    .withTypes("document") 
    .withQuery(queryBuilder) 
    .withPageable(new PageRequest(page, pageSize)); 
elasticsearchTemplate.queryForPage(searchBuilder.build, 
            Document.class, 
            new SearchResultMapper() { 
            //realisation omitted }); 

搜索是一个非常有趣的和大量的话题。我试图尽可能简短地回答,因为这可能会导致令人困惑的时刻 - 请不要犹豫。