[Java]-Elastic中suggest查询建议


查询建议(suggest)是为用户提供良好的使用体验。主要包括: 拼写检查; 自动建议查询词(自动补全)。

官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-suggesters.html#。

查询建议API

查询建议也是使用_search端点地址。在DSL中suggest节点来定义需要的建议查询。

单个建议查询词

POST _search
{
  "query" : {
    "match": {
      "message": "tring out Elasticsearch"
    }
  },
  "suggest" : { <!-- 定义建议查询 -->
    "my-suggestion" : { <!-- 一个建议查询名 -->
      "text" : "tring out Elasticsearch", <!-- 查询文本 -->
      "term" : { <!-- 使用词项建议器 -->
        "field" : "message" <!-- 指定在哪个字段上获取建议词 -->
      }
    }
  }
}

多个建议查询词

可以多个建议词一起查询:

POST _search
{
  "suggest": {
    "my-suggest-1" : {
      "text" : "tring out Elasticsearch",
      "term" : {
        "suggest_mode": "missing",      
        "field" : "message"
      }
    },
    "my-suggest-2" : {
      "text" : "kmichy",
      "term" : {
        "field" : "user"
      }
    }
  }
}

也可以多个查询使用同一个查询文本:

POST _search
{
  "suggest": {
    "text" : "tring out Elasticsearch",
    "my-suggest-1" : {
      "term" : {
        "field" : "message"
      }
    },
    "my-suggest-2" : {
       "term" : {
        "field" : "user"
       }
    }
  }
}

Suggester

Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回。 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester,分别是:

  • Term Suggester
  • Phrase Suggester
  • Completion Suggester
  • Context Suggester

Term suggester

对输入的文本进行分词,为每个词进行模糊匹配查询提供词项建议。对于在索引中存在词默认不提供建议词,不存在的词则根据模糊查询结果进行排序后取一定数量的建议词。

项名说明
text输入文本(用户的输入),根据此文本查找建议
field要查询的字段
analyzer指定分词器
size每个词返回的最大建议词数量
sort建议词的排序方式:
1. score:先按评分排序,再按文档频率、term顺序排;
2. frequency:先按文档频率排序,再按评分、term顺序排
suggest_mode建议模式(控制提供建议词的方式):
1. missing:默认方式,仅在‘要搜索词项’不在索引中存在时,才提供建议词;
2. popular:仅提供频率比‘要搜索词项’高的建议词;
3. always:总是提供建议词;
public void termSuggestSearch(String index, String field, String keyword) {
    try (RestHighLevelClient rhlClient = ESClient.getClient()) {
        TermSuggestionBuilder termSuggestion = SuggestBuilders.termSuggestion(field);
        termSuggestion.text(keyword);
        termSuggestion.size(5);
        termSuggestion.suggestMode(TermSuggestionBuilder.SuggestMode.ALWAYS);
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        String suggestName = "sugName";
        suggestBuilder.addSuggestion(suggestName, termSuggestion);

        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.suggest(suggestBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);
        Suggest suggest = response.getSuggest();
        if (suggest != null) {
            Suggest.Suggestion result = suggest.getSuggestion(suggestName);
            for (Object term : result.getEntries()) {
                if(term instanceof TermSuggestion.Entry) {
                    TermSuggestion.Entry entry = (TermSuggestion.Entry)term;
                    entry.getOptions().forEach(z->{
                        System.out.println("Text: " + z.getText() + ", freq: " + z.getFreq() + ", score: " + z.getScore());
                    });
                }else {
                    System.out.println("It is not termSuggestion.Entry: " + term);
                }
            }
        }
    } catch (Exception ex) {
        System.out.println(index + " query fail: " + ex);
    }
}

参数

字段名称说明
max_edits表示被选为建议的edit distance的最大值,只能是1,2之间的数(可以是小数),默认是2
prefix_length表示被选为建议的最小前缀字符的长度,默认为1,增加这个长度可以提高拼写检查的性能,通常拼写错误不会发生在术语的最前面
min_word_length表示推荐文本的最小长度,默认为4
shard_size设置从每个分片检索的建议的最大数量。在reduce阶段,根据size选项只返回前N个建议。默认是和size选项一样
max_inspections表示一个因子,这个参数和shard_size参数相乘以便在分片级别检查更多的候选者的拼写错误,参数默认为5
min_doc_freq表示一个建议中应包含文档数目的最小限制,可以指定为一个确切的数或文档数的相对百分比,默认是0(即不开启此功能)
max_term_freq表示推荐文本可以包含的文档数目的最大限制,可以是一个代表文档频率的确切值,也可以是一个相对百分数(比如0.4),默认是0.01f。这个参数可以用来排除高频术语的拼写检查
string_distance表示一个字符串距离用于和推荐内容相比它们之间的相似性,这个参数可能的值有5个:
internal:表示默认的基于damerau_levenshtein算法,但在比较字符串距离内的索引已经做过高度优化
damerau_levenshtein:是一种基于Damerau-Levenshtein算法的字符串距离算法
levenshtein:是一种基于Levenshtein edit distance算法的字符串距离算法
jaro_winkler:是一种基于Jaro-Winkler算法的字符串距离算法
ngram:是一种基于字符连词的字符串距离算法

phrase suggester

短语建议,在term的基础上,考量多个term间的关系(是否同时出现在索引的原文里,相邻程度,以及词频等):

public void phraseSuggestSearch(String index, String field, String keyword) {
    try (RestHighLevelClient rhlClient = ESClient.getClient()) {
        PhraseSuggestionBuilder phraseSuggestion = SuggestBuilders.phraseSuggestion(field);
        phraseSuggestion.text(keyword);
        phraseSuggestion.size(5);
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        String suggestName = "sugName";
        suggestBuilder.addSuggestion(suggestName, phraseSuggestion);

        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.suggest(suggestBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);
        Suggest suggest = response.getSuggest();
        if (suggest != null) {
            Suggest.Suggestion result = suggest.getSuggestion(suggestName);
            for (Object term : result.getEntries()) {
                if(term instanceof PhraseSuggestion.Entry) {
                    PhraseSuggestion.Entry entry = (PhraseSuggestion.Entry)term;
                    entry.getOptions().forEach(z->{
                        System.out.println("Text: " + z.getText() + ", score: " + z.getScore());
                    });
                }else {
                    System.out.println("It is not phraseSuggestion.Entry: " + term);
                }
            }
        }
    } catch (Exception ex) {
        System.out.println(index + " query fail: " + ex);
    }
}

completion suggester

Completion Suggester提供自动完成/随类型搜索的功能;这是一种导航特性,可以在用户键入时引导他们找到相关结果,提高搜索精度。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在。

为了使用自动补全,索引中用来提供补全建议的字段需特殊设计,字段类型为 completion。

搜索框实现

要实现搜索框的补全/纠错功能:

  • 在用户刚开始输入的过程中,使用Completion Suggester进行关键词前缀匹配,刚开始匹配项会比较多,随着用户输入字符增多,匹配项越来越少。
  • 如果用户输入比较精准,可能Completion Suggester的结果已经够好,用户已经可以看到理想的备选项了。 如果Completion Suggester已经到了零匹配,那么可以猜测是否用户有输入错误,这时候可以尝试一下Phrase Suggester。如果Phrase Suggester没有找到任何option,开始尝试term Suggester。
  • 精准程度上(Precision)看: Completion > Phrase > term, 而召回率上(Recall)则反之。从性能上看,Completion Suggester是最快的,如果能满足业务需求,只用Completion Suggester做前缀匹配是最理想的。Phrase和Term由于是做倒排索引的搜索,相比较而言性能应该要低不少,应尽量控制suggester用到的索引的数据量,最理想的状况是经过一定时间预热后,索引可以全量map到内存。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
spring-boot-starter-data-elasticsearch8是一个用于在Spring Boot应用集成Elasticsearch的starter包。它提供了一组简化的API和配置,使得在应用使用Elasticsearch进行数据存储和检索变得更加方便。 在该starter包,模糊查询可以通过使用Elasticsearch的QueryBuilders来实现。QueryBuilders是Elasticsearch提供的一个构建查询的工具类,可以用于构建各种类型的查询条件。 要实现模糊查询,可以使用QueryBuilders提供的模糊查询方法之一,比如fuzzyQuery()。该方法可以根据指定的字段和模糊度来进行模糊查询。以下是一个示例代码: ```java import org.elasticsearch.index.query.QueryBuilders; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; // 创建NativeSearchQueryBuilder对象 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加模糊查询条件 queryBuilder.withQuery(QueryBuilders.fuzzyQuery("fieldName", "keyword")); // 创建NativeSearchQuery对象 NativeSearchQuery searchQuery = queryBuilder.build(); // 执行查询 List<YourEntity> results = elasticsearchRestTemplate.queryForList(searchQuery, YourEntity.class); ``` 在上述代码,我们使用了NativeSearchQueryBuilder来构建查询条件,然后使用ElasticsearchRestTemplate执行查询。其,"fieldName"是要进行模糊查询的字段名,"keyword"是要查询的关键词。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值