ElasticSearch的自动补全功能(拼音分词器、自定义分词器、DSL实现自动补全 ...

打印 上一主题 下一主题

主题 681|帖子 681|积分 2043

视频教程:SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,体系详解springcloud微服务技术栈课程|黑马步伐员Java微服务

阅读本文前可以先阅读以下文章:


  • ElasticSearch快速入门——上篇(认识ElasticSearch、安装ElasticSearch、安装kibana、IK分词器、ElasticSearch中的基本概念、索引库操作、文档操作)
  • ElasticSearch快速入门——下篇(在Java代码中操作ElasticSearch、JavaRestClient、操作索引库、操作文档、DSL查询、JavaRestClient查询、数据聚合)
  • 通过docker启动ElasticSearch后为ElasticSearch设置用户和暗码
1. 什么是自动补全

ElasticSearch 中的自动补全跟我们明白的自动补全不太一样,为了各人明白,我们来看一个案例

当我们在搜索框输入 sj 时,搜索框下方会表现以 sj 拼音首字母开头的词条(如手机、湿巾、数据线、史记、书架等),这个功能被称为自动补全
自动补全功能可以让用户尽大概地搜索到想要的东西,而不必要打出完整的内容
2. 拼音分词器

要想实现自动补全功能,我们必要先学习一下拼音分词器,由于自动补全功能是基于拼音分词器实现的
2.1 初识拼音分词器

拼音分词器的官网:analysis-pinyin
拼音分词器跟我们学过的 IK 分词器相似,都是 ElasticSearch 的一个插件
2.2 下载拼音分词器

下载地点:v7.17.18


本次演示使用的 ElasticSearch 版本为 7.17.18
其它 ElasticSearch 版本对应的拼音分词器的下载地点:Tags
2.3 安装拼音分词器

解压完成之后,将拼音分词器上传到 ElasticSearch 的 plugin 目次下(本次演示是通过 docker 安装 ElasticSearch 的)

先将拼音分词器上传到服务器,一样平常是当前用户的目次
  1. cd ~
复制代码
接着将拼音分词器复制到 ElasticSearch 的 plugin 的目次下
  1. sudo cp elasticsearch-analysis-pinyin-7.17.18 -r /var/lib/docker/volumes/elasticsearch-plugins/_data
复制代码
末了重启 ElasticSearch 容器
  1. sudo docker restart elasticsearch
复制代码
2.4 测试拼音分词器

我们在 Kibana 提供的控制台中测试拼音分词器是否生效

在欣赏器打开 Kibana 提供的控制台
  1. http://127.0.0.1:5601/app/dev_tools#/console
复制代码
输入以下内容测试拼音分词器是否生效
  1. POST /_analyze
  2. {
  3.   "text": [
  4.     "练习时长两年半"
  5.   ],
  6.   "analyzer": "pinyin"
  7. }
复制代码
测试结果如下,主要包含两部分内容:

  • 每个字的完整拼音
  • 每个字的拼音首字母的合并

  1. {
  2.   "tokens" : [
  3.     {
  4.       "token" : "lian",
  5.       "start_offset" : 0,
  6.       "end_offset" : 0,
  7.       "type" : "word",
  8.       "position" : 0
  9.     },
  10.     {
  11.       "token" : "lxsclnb",
  12.       "start_offset" : 0,
  13.       "end_offset" : 0,
  14.       "type" : "word",
  15.       "position" : 0
  16.     },
  17.     {
  18.       "token" : "xi",
  19.       "start_offset" : 0,
  20.       "end_offset" : 0,
  21.       "type" : "word",
  22.       "position" : 1
  23.     },
  24.     {
  25.       "token" : "shi",
  26.       "start_offset" : 0,
  27.       "end_offset" : 0,
  28.       "type" : "word",
  29.       "position" : 2
  30.     },
  31.     {
  32.       "token" : "chang",
  33.       "start_offset" : 0,
  34.       "end_offset" : 0,
  35.       "type" : "word",
  36.       "position" : 3
  37.     },
  38.     {
  39.       "token" : "liang",
  40.       "start_offset" : 0,
  41.       "end_offset" : 0,
  42.       "type" : "word",
  43.       "position" : 4
  44.     },
  45.     {
  46.       "token" : "nian",
  47.       "start_offset" : 0,
  48.       "end_offset" : 0,
  49.       "type" : "word",
  50.       "position" : 5
  51.     },
  52.     {
  53.       "token" : "ban",
  54.       "start_offset" : 0,
  55.       "end_offset" : 0,
  56.       "type" : "word",
  57.       "position" : 6
  58.     }
  59.   ]
  60. }
复制代码
3. 自定义分词器

3.1 拼音分词器存在的题目

拼音分词器还无法正常用于生产环境,由于拼音分词器存在一些题目
以 “训练时长两年半” 这句话为例,拼音分词器存在以下题目:

  • “训练时长两年半” 这句话没有被分词,而是作为一个整体出现
  • 把 “训练时长两年半” 这句话中的每一个字都形成了一个拼音(用处不大)
  • 分词后的结果只剩下拼音,没有汉字

其实我们很少使用拼音搜索,大多数情况下我们都是使用中文去搜索的,分词后有拼音只是锦上添花,分词后的结果中汉字是必须保留的,所以我们必要对拼音分词器做一些配置,也就是自定义分词器
3.2 分词器(analyzer)的组成

ElasticSearch 中分词器(analyzer)的组成有三部分:


  • character filters:在 tokenizer 之前对文本进行处理,比方删除字符、替换字符
  • tokenizer:将文本按照一定的规则切割成词条(term),比方 keyword(不分词)、ik_smart 等
  • tokenizer filter:将 tokenizer 输出的词条做进一步处理,比方巨细写转换、同义词处理、拼音处理等

3.3 如何自定义分词器

   要想自定义分词器,一定要在创建索引库的时候去设置
  我们可以在创建索引库时,通过 settings 来配置自定义的 analyzer(分词器)
自定义分词器时可以只设置分词器(analyzer)的某个部分

  1. PUT /test
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": {
  6.         "my_analyzer": {
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "pinyin"
  9.         }
  10.       }
  11.     }
  12.   }
  13. }
复制代码
tokenizer 我们使用 ik_max_word,先分词,分好词后再将词条交给拼音分词器处理,如许做可以解决拼音分词器没有分词的题目
但是拼音分词器还存在两个题目:分词后的每一个字都形成了一个拼音、分词后的结果只剩下拼音,没有汉字
3.4 拼音分词器的可选参数

我们必要对拼音分词器做进一步的定制
在拼音分词器的官网上,给出了很多的可选参数(Optional Parameters)

参数名称寄义keep_first_letter启用后,只保留每个汉字的第一个字母。比方,刘德华变为ldh。默认:true。keep_separate_first_letter启用后,保留每个汉字的第一个字母,并分别表现。比方,刘德华变为l,d,h。默认:false。留意:这大概会因词频增长查询的含糊度。limit_first_letter_length设置第一个字母结果的最大长度。默认:16。keep_full_pinyin启用后,保留每个汉字的完整拼音。比方,刘德华变为[liu,de,hua]。默认:true。keep_joined_full_pinyin启用后,将每个汉字的完整拼音连接起来。比方,刘德华变为[liudehua]。默认:false。keep_none_chinese保留结果中的非汉字字母或数字。默认:true。keep_none_chinese_together保留非汉字字母在一起。默认:true。比方,DJ音乐家变为DJ,yin,yue,jia。当设置为false时,DJ音乐家变为D,J,yin,yue,jia。留意:必要先启用keep_none_chinese。keep_none_chinese_in_first_letter在首字母中保留非汉字字母。比方,刘德华AT2016变为ldhat2016。默认:true。keep_none_chinese_in_joined_full_pinyin在连接的完整拼音中保留非汉字字母。比方,刘德华2016变为liudehua2016。默认:false。none_chinese_pinyin_tokenize如果非汉字字母是拼音,将其拆分为单独的拼音词。默认:true。比方,liudehuaalibaba13zhuanghan变为liu,de,hua,a,li,ba,ba,13,zhuang,han。留意:必要先启用keep_none_chinese和keep_none_chinese_together。keep_original启用后,保留原始输入。默认:false。lowercase将非汉字字母转换为小写。默认:true。trim_whitespace默认:true。remove_duplicated_term启用后,移除重复的词以节省索引空间。比方,de的变为de。默认:false。留意:大概与位置相干的查询受到影响。ignore_pinyin_offset在6.0版本之后,偏移量受到严格限制,不允许重叠的词。通过此参数,将允许重叠的词,忽略偏移量。请留意,全部与位置相干的查询或高亮将变得不精确。如果必要偏移量,请设置为false。默认:true。 3.5 配置自定义分词器的tokenizer和filter


  1. PUT /test
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": {
  6.         "my_analyzer": {
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "py"
  9.         }
  10.       },
  11.       "filter": {
  12.         "py": {
  13.           "type": "pinyin",
  14.           "keep_full_pinyin": false,
  15.           "keep_joined_full_pinyin": true,
  16.           "keep_original": true,
  17.           "limit_first_letter_length": 16,
  18.           "remove_duplicated_term": true,
  19.           "none_chinese_pinyin_tokenize": false
  20.         }
  21.       }
  22.     }
  23.   }
  24. }
复制代码
创建一个自定义的分词器my_analyzer,使用ik_max_word分词器进行中文分词,并通过pinyin过滤器将中文词条转换为拼音,保留了原始中文词条和连接起来的全拼,同时限制了首字母长度并移除重复的词条
3.6 如何使用自定义分词器

自定义分词器创建好了之后,该怎么使用呢
要使用自定义分词器,我们必要在定义索引库字段(Mapping)的时候使用

  1. PUT /test
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": {
  6.         "my_analyzer": {
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "py"
  9.         }
  10.       },
  11.       "filter": {
  12.         "py": {
  13.           "type": "pinyin",
  14.           "keep_full_pinyin": false,
  15.           "keep_joined_full_pinyin": true,
  16.           "keep_original": true,
  17.           "limit_first_letter_length": 16,
  18.           "remove_duplicated_term": true,
  19.           "none_chinese_pinyin_tokenize": false
  20.         }
  21.       }
  22.     }
  23.   },
  24.   "mappings": {
  25.     "properties": {
  26.       "name": {
  27.         "type": "text",
  28.         "analyzer": "my_analyzer"
  29.       }
  30.     }
  31.   }
  32. }
复制代码
3.7 测试自定义分词器

3.7.1 直接测试

  1. POST /test/_analyze
  2. {
  3.   "text": [
  4.     "练习时长两年半"
  5.   ],
  6.   "analyzer": "my_analyzer"
  7. }
复制代码
测试结果

  1. {
  2.   "tokens" : [
  3.     {
  4.       "token" : "练习",
  5.       "start_offset" : 0,
  6.       "end_offset" : 2,
  7.       "type" : "CN_WORD",
  8.       "position" : 0
  9.     },
  10.     {
  11.       "token" : "lianxi",
  12.       "start_offset" : 0,
  13.       "end_offset" : 2,
  14.       "type" : "CN_WORD",
  15.       "position" : 0
  16.     },
  17.     {
  18.       "token" : "lx",
  19.       "start_offset" : 0,
  20.       "end_offset" : 2,
  21.       "type" : "CN_WORD",
  22.       "position" : 0
  23.     },
  24.     {
  25.       "token" : "时长",
  26.       "start_offset" : 2,
  27.       "end_offset" : 4,
  28.       "type" : "CN_WORD",
  29.       "position" : 1
  30.     },
  31.     {
  32.       "token" : "shichang",
  33.       "start_offset" : 2,
  34.       "end_offset" : 4,
  35.       "type" : "CN_WORD",
  36.       "position" : 1
  37.     },
  38.     {
  39.       "token" : "sc",
  40.       "start_offset" : 2,
  41.       "end_offset" : 4,
  42.       "type" : "CN_WORD",
  43.       "position" : 1
  44.     },
  45.     {
  46.       "token" : "两年",
  47.       "start_offset" : 4,
  48.       "end_offset" : 6,
  49.       "type" : "CN_WORD",
  50.       "position" : 2
  51.     },
  52.     {
  53.       "token" : "liangnian",
  54.       "start_offset" : 4,
  55.       "end_offset" : 6,
  56.       "type" : "CN_WORD",
  57.       "position" : 2
  58.     },
  59.     {
  60.       "token" : "ln",
  61.       "start_offset" : 4,
  62.       "end_offset" : 6,
  63.       "type" : "CN_WORD",
  64.       "position" : 2
  65.     },
  66.     {
  67.       "token" : "两",
  68.       "start_offset" : 4,
  69.       "end_offset" : 5,
  70.       "type" : "COUNT",
  71.       "position" : 3
  72.     },
  73.     {
  74.       "token" : "liang",
  75.       "start_offset" : 4,
  76.       "end_offset" : 5,
  77.       "type" : "COUNT",
  78.       "position" : 3
  79.     },
  80.     {
  81.       "token" : "l",
  82.       "start_offset" : 4,
  83.       "end_offset" : 5,
  84.       "type" : "COUNT",
  85.       "position" : 3
  86.     },
  87.     {
  88.       "token" : "年半",
  89.       "start_offset" : 5,
  90.       "end_offset" : 7,
  91.       "type" : "CN_WORD",
  92.       "position" : 4
  93.     },
  94.     {
  95.       "token" : "nianban",
  96.       "start_offset" : 5,
  97.       "end_offset" : 7,
  98.       "type" : "CN_WORD",
  99.       "position" : 4
  100.     },
  101.     {
  102.       "token" : "nb",
  103.       "start_offset" : 5,
  104.       "end_offset" : 7,
  105.       "type" : "CN_WORD",
  106.       "position" : 4
  107.     }
  108.   ]
  109. }
复制代码
3.7.2 插入文档测试

测试数据如下(狮子和虱子的拼音是一样的
  1. POST /test/_doc/1
  2. {
  3.   "id": 1,
  4.   "name": "狮子"
  5. }
  6. POST /test/_doc/2
  7. {
  8.   "id": 2,
  9.   "name": "虱子"
  10. }
复制代码
我们先通过拼音 shizi 来搜索
  1. GET /test/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "name": "shizi"
  6.     }
  7.   }
  8. }
复制代码
成功搜索出狮子和虱子

但如果我们搜索的内容是掉入狮子笼怎么办呢
  1. GET /test/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "name": "掉入狮子笼怎么办"
  6.     }
  7.   }
  8. }
复制代码

从搜索结果中我们可以发现,我们明明搜索的是狮子,怎么虱子也搜索出来了?
这阐明我们自定义的分词器有题目,在用拼音搜索时确实没题目,但是在用中文搜索时却搜出了同音词
3.8 使用自定义分词器要留意的事项

拼音分词器适合在创建倒排索引的时候使用,但不能在搜索的时候使用

创建倒排索引时


用户搜索狮子,搜索结果中居然出现了虱子

所以,我们在创建倒排索引时使用的分词器要和搜索时使用的分词器分开
怎么分开呢,在创建倒排索引时使用 my_analyzer 分词器,搜索时使用 ik_smart 分词器

  1. PUT /test
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": {
  6.         "my_analyzer": {
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "py"
  9.         }
  10.       },
  11.       "filter": {
  12.         "py": {
  13.           "type": "pinyin",
  14.           "keep_full_pinyin": false,
  15.           "keep_joined_full_pinyin": true,
  16.           "keep_original": true,
  17.           "limit_first_letter_length": 16,
  18.           "remove_duplicated_term": true,
  19.           "none_chinese_pinyin_tokenize": false
  20.         }
  21.       }
  22.     }
  23.   },
  24.   "mappings": {
  25.     "properties": {
  26.       "name": {
  27.         "type": "text",
  28.         "analyzer": "my_analyzer",
  29.         "search_analyzer": "ik_smart"
  30.       }
  31.     }
  32.   }
  33. }
复制代码
我们删除 test 索引库之后,重写创建 test 索引库进行测试
  1. DELETE /test
复制代码
  1. GET /test/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "name": "掉入狮子笼怎么办"
  6.     }
  7.   }
  8. }
复制代码
测试结果如下(可以看到,搜索结果中没有虱子了)

4. DSL实现自动补全查询

ElasticSearch 提供了 Completion suggester 查询来实现自动补全功能,这个查询会匹配以用户输入内容开头的词条并
返回
4.1 字段的范例的束缚

为了提高补全查询的效率,对于文档中字段的范例有一些束缚:

  • 参与补全查询的字段必须是 completion 范例
  • 字段的内容一样平常是用来补全的多个词条形成的数组

4.2 查询语法


索引库
  1. PUT test2
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "title":{
  6.         "type": "completion"
  7.       }
  8.     }
  9.   }
  10. }
复制代码
测试数据
  1. POST test2/_doc
  2. {
  3.   "title": ["Sony", "WH-1000XM3"]
  4. }
  5. POST test2/_doc
  6. {
  7.   "title": ["SK-II", "PITERA"]
  8. }
  9. POST test2/_doc
  10. {
  11.   "title": ["Nintendo", "switch"]
  12. }
复制代码
实行查询操作
  1. POST /test2/_search
  2. {
  3.   "suggest": {
  4.     "title_suggest": {
  5.       "text": "s",
  6.       "completion": {
  7.         "field": "title",
  8.         "skip_duplicates": true,
  9.         "size": 10
  10.       }
  11.     }
  12.   }
  13. }
复制代码
查询结果(查询结果中包含了文档的原始信息)

5. 自动补全案例

我们来做一个关于旅店数据的自动补全案例
5.1 预备工作

5.1.1 创建hotel索引库

  1. PUT /hotel
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": {
  6.         "text_anlyzer": {
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "py"
  9.         },
  10.         "completion_analyzer": {
  11.           "tokenizer": "keyword",
  12.           "filter": "py"
  13.         }
  14.       },
  15.       "filter": {
  16.         "py": {
  17.           "type": "pinyin",
  18.           "keep_full_pinyin": false,
  19.           "keep_joined_full_pinyin": true,
  20.           "keep_original": true,
  21.           "limit_first_letter_length": 16,
  22.           "remove_duplicated_term": true,
  23.           "none_chinese_pinyin_tokenize": false
  24.         }
  25.       }
  26.     }
  27.   },
  28.   "mappings": {
  29.     "properties": {
  30.       "id": {
  31.         "type": "keyword"
  32.       },
  33.       "name": {
  34.         "type": "text",
  35.         "analyzer": "text_anlyzer",
  36.         "search_analyzer": "ik_smart",
  37.         "copy_to": "all"
  38.       },
  39.       "address": {
  40.         "type": "keyword",
  41.         "index": false
  42.       },
  43.       "price": {
  44.         "type": "integer"
  45.       },
  46.       "score": {
  47.         "type": "integer"
  48.       },
  49.       "brand": {
  50.         "type": "keyword",
  51.         "copy_to": "all"
  52.       },
  53.       "city": {
  54.         "type": "keyword"
  55.       },
  56.       "starName": {
  57.         "type": "keyword"
  58.       },
  59.       "business": {
  60.         "type": "keyword",
  61.         "copy_to": "all"
  62.       },
  63.       "location": {
  64.         "type": "geo_point"
  65.       },
  66.       "pic": {
  67.         "type": "keyword",
  68.         "index": false
  69.       },
  70.       "all": {
  71.         "type": "text",
  72.         "analyzer": "text_anlyzer",
  73.         "search_analyzer": "ik_smart"
  74.       },
  75.       "suggestion": {
  76.         "type": "completion",
  77.         "analyzer": "completion_analyzer",
  78.         "search_analyzer": "ik_smart"
  79.       }
  80.     }
  81.   }
  82. }
复制代码
5.1.2 导入测试工程

测试工程的 Gitee 地点:hotel-demo
5.1.3 导入旅店数据到数据库中

SQL 脚本在测试工程的 doc 目次下

5.1.4 将数据库中的数据导入到ElasticSearch

导入数据前,更改与连接 ElasticSearch 相干的信息(如果 ElasticSearch 没有设置暗码,可以去除 setHttpClientConfigCallback 代码)

运行 HotelDocumentTest 测试类中的 testBulkRequest 方法,将数据库中的数据导入到 ElasticSearch

在 Kibana 提供的控制台检查数据是否导入成功
  1. GET /hotel/_search
  2. {
  3.   "query": {
  4.     "match_all": {}
  5.   }
  6. }
复制代码

5.2 测试自动补全功能

在 Kibana 提供的控制台测试自动补全功能
  1. GET /hotel/_search
  2. {
  3.   "suggest": {
  4.     "suggestions": {
  5.       "text": "s",
  6.       "completion": {
  7.         "field": "suggestion",
  8.         "skip_duplicates": true,
  9.         "size": 10
  10.       }
  11.     }
  12.   }
  13. }
复制代码
测试结果

6. RestAPI实现自动补全查询

构建请求参数的 API

结果解析

  1. import cn.itcast.hotel.service.IHotelService;
  2. import org.apache.http.HttpHost;
  3. import org.apache.http.auth.AuthScope;
  4. import org.apache.http.auth.UsernamePasswordCredentials;
  5. import org.apache.http.impl.client.BasicCredentialsProvider;
  6. import org.elasticsearch.action.search.SearchRequest;
  7. import org.elasticsearch.action.search.SearchResponse;
  8. import org.elasticsearch.client.RequestOptions;
  9. import org.elasticsearch.client.RestClient;
  10. import org.elasticsearch.client.RestClientBuilder;
  11. import org.elasticsearch.client.RestHighLevelClient;
  12. import org.elasticsearch.search.suggest.Suggest;
  13. import org.elasticsearch.search.suggest.SuggestBuilder;
  14. import org.elasticsearch.search.suggest.SuggestBuilders;
  15. import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
  16. import org.junit.jupiter.api.AfterEach;
  17. import org.junit.jupiter.api.BeforeEach;
  18. import org.junit.jupiter.api.Test;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.boot.test.context.SpringBootTest;
  21. import java.io.IOException;
  22. import java.util.List;
  23. @SpringBootTest
  24. class HotelSuggestionTest {
  25.     private RestHighLevelClient restHighLevelClient;
  26.     @Autowired
  27.     private IHotelService hotelService;
  28.     @Test
  29.     void testSuggestion() throws IOException {
  30.         // 1.准备SearchRequest
  31.         SearchRequest searchRequest = new SearchRequest("hotel");
  32.         // 2.准备DSL
  33.         searchRequest.source().suggest(new SuggestBuilder().addSuggestion(
  34.                 "suggestions",
  35.                 SuggestBuilders.completionSuggestion("suggestion")
  36.                         .prefix("h")
  37.                         .skipDuplicates(true)
  38.                         .size(10)
  39.         ));
  40.         // 3.发送请求
  41.         SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  42.         // 4.解析结果
  43.         // 4.1.获取suggest对象
  44.         Suggest suggest = searchResponse.getSuggest();
  45.         // 4.2.根据名称获取suggestion对象
  46.         CompletionSuggestion suggestion = suggest.getSuggestion("suggestions");
  47.         // 4.3.获取options
  48.         List<CompletionSuggestion.Entry.Option> options = suggestion.getOptions();
  49.         // 4.4.遍历
  50.         for (CompletionSuggestion.Entry.Option option : options) {
  51.             System.out.println("option.getText().string() = " + option.getText().string());
  52.         }
  53.     }
  54.     @BeforeEach
  55.     void setUp() {
  56.         // 用户名和密码
  57.         String username = "elastic";
  58.         String password = "tF8RGg2vd0FAzgkK";
  59.         final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  60.         credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
  61.         RestClientBuilder restClientBuilder = RestClient
  62.                 .builder(new HttpHost("127.0.0.1", 9200, "http"))
  63.                 .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
  64.         restHighLevelClient = new RestHighLevelClient(restClientBuilder);
  65.     }
  66.     @AfterEach
  67.     void tearDown() throws IOException {
  68.         restHighLevelClient.close();
  69.     }
  70. }
复制代码
7. 综合案例:实现搜索框自动补全

测试工程已实现搜索框自动补全,启动测试工程后,在欣赏器中查看搜索框的自动补全效果
  1. http://localhost:8089/
复制代码


前端源代码的 Gitee 地点:auto-complete

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

李优秀

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表