【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案

这篇具有很好参考价值的文章主要介绍了【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简述

业务开发中经常会遇到这样一种情况,用户在搜索框输入时要实时展示搜索相关的结果。要实现这个场景常用的方案有Completion Suggester、search_as_you_type。那么这两种方式有什么区别呢?一起来了解下。

环境说明:

数据量:9000w+
es版本:7.10.1
脚本执行工具:kibana

Completion Suggester和search_as_you_type的区别

1.Completion Suggester是基于前缀匹配、且数据结构存储在内存中,超级快,缺点是耗内存
2.search_as_you_type可以是前缀、中缀匹配,可以很快,但是要选好查询方式
3.Api调用方式不同,Completion Suggester是通过Suggest语句查询,search_as_you_type和常规查询方式一致

举个栗子

如何实现前缀匹配需求

使用Completion Suggester,示例如下:

  1. 创建索引
PUT /es_demo
{
  "mappings": {
    "properties": {
      "title_comp": {
        "type": "completion",
        "analyzer": "standard"
      }
    }
  }
}
  1. 初始化数据
POST _bulk
{"index":{"_index":"es_demo","_id":"1"}}
{"title_comp": "愤怒的小鸟"}
{"index":{"_index":"es_demo","_id":"2"}}
{"title_comp": "最后一只渡渡鸟"}
{"index":{"_index":"es_demo","_id":"3"}}
{"title_comp": "今天不加班啊"}
{"index":{"_index":"es_demo","_id":"4"}}
{"title_comp": "愤怒的青年"}
{"index":{"_index":"es_demo","_id":"5"}}
{"title_comp": "最后一只996程序猿"}
{"index":{"_index":"es_demo","_id":"6"}}
{"title_comp": "今日无事,勾栏听曲"}
  1. 查询DSL
    通过前缀查询,查找以“愤怒”开头的字符串
GET /es_demo/_search
{
  "suggest": {
    "title_suggest": {
      "prefix": "愤怒",
      "completion": {
        "field": "title_comp"
      }
    }
  }
}
  1. 查询代码demo
@SpringBootTest
public class SuggestTest {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void testComp() {
        List<Map<String, Object>> list = suggestComplete("愤怒");
        list.forEach(m -> System.out.println("[" + m.get("title_comp") + "]"));
    }

    public List<Map<String, Object>> suggestComplete(String keyword) {
        CompletionSuggestionBuilder completionSuggestionBuilder = SuggestBuilders.completionSuggestion("title_comp");
        completionSuggestionBuilder.size(5)
                //跳过重复的
                .skipDuplicates(true);

        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("suggest_title", completionSuggestionBuilder)
                .setGlobalText(keyword);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.suggest(suggestBuilder);

        SearchRequest searchRequest = new SearchRequest("es_demo").source(searchSourceBuilder);

        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            CompletionSuggestion completionSuggestion = response.getSuggest().getSuggestion("suggest_title");

            List<Map<String, Object>> suggestList = new LinkedList<>();
            for (CompletionSuggestion.Entry.Option option : completionSuggestion.getOptions()) {
                Map<String, Object> map = new HashMap<>();
                map.put("title_comp", option.getHit().getSourceAsMap().get("title_comp"));
                suggestList.add(map);
            }

            return suggestList;
        } catch (IOException e) {
            throw new RuntimeException("ES查询出错");
        }
    }
}

查询结果:

[愤怒的小鸟]
[愤怒的青年]

如何实现中缀匹配需求

使用search_as_you_type,此处提供了hanlp_index和standard两种分词器的字段示例。示例如下:

  1. 创建索引
PUT /es_search_as_you_type
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "han": {
            "type": "search_as_you_type",
            "analyzer": "hanlp_index"
          },
          "stan": {
            "type": "search_as_you_type",
            "analyzer": "standard"
          }
        }
      }
    }
  }
}
  1. 初始化数据
POST _bulk
{"index":{"_index":"es_search_as_you_type","_id":"1"}}
{"title": "愤怒的小鸟"}
{"index":{"_index":"es_search_as_you_type","_id":"2"}}
{"title": "最后一只渡渡鸟"}
{"index":{"_index":"es_search_as_you_type","_id":"3"}}
{"title": "今天不加班啊"}
{"index":{"_index":"es_search_as_you_type","_id":"4"}}
{"title": "愤怒的青年"}
{"index":{"_index":"es_search_as_you_type","_id":"5"}}
{"title": "最后一只996程序猿"}
{"index":{"_index":"es_search_as_you_type","_id":"6"}}
{"title": "今日无事,勾栏听曲"}
  1. 查询DSL
GET /es_search_as_you_type/_search
{
  "query": {
    "match": {
      "title.stan": {
        "query": "的小",
        "operator": "and"
      }
    }
  }
}
  1. 查询代码demo
@SpringBootTest
public class SuggestTest {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void testSearchAsYouType() {
        List<Map<String, Object>> list = suggestSearchAsYouType("的小");
        list.forEach(m -> System.out.println("[" + m.get("title") + "]"));
    }

    public List<Map<String, Object>> suggestSearchAsYouType(String keyword) {
        //这里使用了search_as_you_type的2gram字段,可以根据自己需求调整配置
        MatchQueryBuilder matchQueryBuilder = matchQuery("title.stan._2gram", keyword).operator(Operator.AND);

        //需要返回的字段
        String[] includeFields = new String[]{"title"};
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(matchQueryBuilder).size(5)
                .fetchSource(includeFields, null)
                .trackTotalHits(false)
                .trackScores(true)
                .sort(SortBuilders.scoreSort());

        SearchRequest searchRequest = new SearchRequest("es_search_as_you_type").source(searchSourceBuilder);

        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            org.elasticsearch.search.SearchHits hits = response.getHits();

            List<Map<String, Object>> suggestList = new LinkedList<>();
            for (org.elasticsearch.search.SearchHit hit : hits) {
                Map<String, Object> map = new HashMap<>();
                map.put("title", hit.getSourceAsMap().get("title").toString());
                suggestList.add(map);
            }
            return suggestList;
        } catch (IOException e) {
            throw new RuntimeException("ES查询出错");
        }
    }
}

查询结果:

[愤怒的小鸟]

分词器说明

查看分词结果的方式

第一种

指定分词器

GET _analyze
{
  "analyzer": "standard",
  "text": [
    "愤怒的小鸟"
  ]
}

第二种

指定使用某个字段的分词器

POST es_search_as_you_type/_analyze
{
  "field": "title.stan",
  "text": [
    "愤怒的青年"
  ]
}

hanlp_index和standard分词器的区别

standard分词器

  • 默认会过滤掉符号
  • 中文以单个字为最小单位,英文则会以空格符或其他符号或中文分隔作为一个单词

例:

GET _analyze
{
  "analyzer": "standard",
  "text": [
    "愤怒的小鸟"
  ]
}

分词结果:

{
  "tokens" : [
    {
      "token" : "愤",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "<IDEOGRAPHIC>",
      "position" : 0
    },
    {
      "token" : "怒",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "<IDEOGRAPHIC>",
      "position" : 1
    },
    {
      "token" : "的",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "<IDEOGRAPHIC>",
      "position" : 2
    },
    {
      "token" : "小",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "<IDEOGRAPHIC>",
      "position" : 3
    },
    {
      "token" : "鸟",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "<IDEOGRAPHIC>",
      "position" : 4
    }
  ]
}

hanlp_index分词器

  • 默认不会过滤符号
  • 通过语义等对字符串进行分词,会分出词语

例:

GET _analyze
{
  "analyzer": "hanlp_index",
  "text": [
    "愤怒的小鸟"
  ]
}

分词结果:

{
  "tokens" : [
    {
      "token" : "愤怒",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "a",
      "position" : 0
    },
    {
      "token" : "的",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "ude1",
      "position" : 1
    },
    {
      "token" : "小鸟",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "n",
      "position" : 2
    }
  ]
}

生产实践中的查询情况

基本都是几百毫秒就解决。ps:如果一条数据字段很多,最好只返回几个需要的字段即可,否则数据传输就要占用较多时间。
【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案

总结

当然,无论是Completion Suggester还是search_as_you_type的查询配置方式都还有很多,例如Completion Suggester的Context Suggester,search_as_you_type的2gram、3gram,还有查询类型match_bool_prefix、match_phrase、match_phrase_prefix等等。各种组合起来都会产生不同的效果,笔者这里只是列举出一种还算可以的方式。关于其他的查询类型和配置如何使用以及分别是怎么工作的,下次有空再聊聊。

官方文档链接

https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-as-you-type.html文章来源地址https://www.toymoban.com/news/detail-587264.html

到了这里,关于【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算术表达式:前缀、中缀表、后缀表达式相互转换

    概念: 三者的区别在于运算符相对于操作数的位置有所不同   前缀表达式 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。   中缀表达式  中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于

    2024年02月05日
    浏览(73)
  • ElasticSearch近实时搜索的实现

    有经验的程序员一定知道,在做并发编程时,控制可变数据的并发访问是个难题。古往今来,各种粗细粒度的锁,信号量,Actor模型等概念层出不穷。而另一流派函数式编程更为彻底,尤其是纯函数式比如Haskell,用不可变数据来彻底解决这个问题。 在ElasticSearch这样主要服务

    2024年04月10日
    浏览(28)
  • ClickHouse与Elasticsearch实时搜索案例

    随着数据的增长和实时性的要求,实时搜索技术变得越来越重要。ClickHouse和Elasticsearch都是流行的实时搜索技术,它们各自具有不同的优势和适用场景。本文将详细介绍ClickHouse与Elasticsearch的实时搜索案例,并分析它们的优缺点。 2.1 ClickHouse ClickHouse是一个高性能的列式数据库

    2024年02月19日
    浏览(30)
  • Elasticsearch 与 GraphQL 整合:构建实时搜索 API

    随着互联网的普及和数据的快速增长,实时搜索已经成为现代网站和应用程序的必不可少的功能。实时搜索可以帮助用户快速找到相关信息,提高用户体验,增加用户留存时间,并提高销售转化率。 Elasticsearch 是一个开源的搜索和分析引擎,基于 Lucene 库,它提供了一个实时

    2024年04月22日
    浏览(22)
  • 基于PHP和Elasticsearch的实时搜索技术应用

    随着互联网的发展和信息的爆炸增长,用户对于快速、精准的搜索需求也越来越高。 传统的数据库查询方式已经无法满足这种需求,而Elasticsearch作为一款开源的实时分布式搜索和分析引擎,正逐渐成为业界广泛使用的解决方案之一。 在本文中,我们将使用PHP作为后端语言,

    2024年02月08日
    浏览(37)
  • ElasticSearch + Canal 开发千万级的实时搜索系统【转】

    我们总结一下新搜索系统需要解决的几个问题: 海量请求。几百万的请求毫无压力,上千万上亿也要可以扛得住。 实时搜索。指的是当一个用户修改了其数据之后,另一个用户能实时地搜索到改用户。 海量请求。要扛得起海量的搜索请求,可以使用ElasticSearch来实现,它是在

    2024年04月09日
    浏览(33)
  • ElasticSearch系列 - 分片内部原理之动态更新索引、近实时搜索、持久化变更、段合并

    01. ElasticSearch 倒排索引是什么? Elasticsearch的倒排索引是一种数据结构,它将每个单词与包含该单词的文档列表相关联。倒排索引的优势在于它可以快速地进行全文搜索和相关性评分。 倒排索引由3个主要部分组成:词项、词汇表、倒排列表。其中词项是索引中最小的存储和查

    2024年02月05日
    浏览(33)
  • Elasticsearch的实时数据分析与报警

    在今天的数据驱动时代,实时数据分析和报警已经成为企业和组织中不可或缺的一部分。Elasticsearch是一个强大的搜索和分析引擎,它可以帮助我们实现实时数据分析和报警。在本文中,我们将深入探讨Elasticsearch的实时数据分析与报警,并提供一些最佳实践和实际应用场景。

    2024年02月20日
    浏览(29)
  • 通过搜索引擎让大模型获取实时数据-实现类似 perplexity 的效果

    汇报一下这周末的工作,主要是开发了一门课程:通过搜索引擎让大模型获取实时数据,第一次开发一门课程,难免会有很多不熟悉和做的不好的地方。 已经训练好的大模型有气数据的局限性,比如 GPT-4,只有 2023年4月之前的数据。关于最新发生的一些事情,它无法回答。

    2024年04月23日
    浏览(56)
  • Elasticsearch数据搜索原理

    Elasticsearch 是一个开源的、基于 Lucene 的分布式搜索和分析引擎,设计用于云计算环境中,能够实现实时的、可扩展的搜索、分析和探索全文和结构化数据。它具有高度的可扩展性,可以在短时间内搜索和分析大量数据。 Elasticsearch 不仅仅是一个全文搜索引擎,它还提供了分布

    2024年02月08日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包