【ElasticSearch】ES自动补全查询与Java接口实现

这篇具有很好参考价值的文章主要介绍了【ElasticSearch】ES自动补全查询与Java接口实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


自动补全就是当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项。

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

1、安装拼音分词器

要实现根据字母做补全,就必须对文档按照拼音分词。GitHub上有相关插件,地址:https://github.com/medcl/elasticsearch-analysis-pinyin,下载和ES对应的版本。

安装步骤:

  • 解压

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

  • 上传到虚拟机中,elasticsearch的plugin目录

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

docker volume ls
docker inspect volumeXXX
  • 重启elasticsearch的容器
docker restar es
  • 测试

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

但上面的拼音分词器也有很明显的缺陷,那就是没有进行词条切割,且汉字没了。

2、自定义分词器

ES的分词器由三部分组成:

character filters:在tokenizer之前对文本进行处理。例如删除字符、替换字符

tokenizer:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smart

tokenizer filter:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等

举个例子:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎
在创建索引库时, 可以通过settings来配置自定义的analyzer(分词器):

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": { // 自定义分词器
        "my_analyzer": {  // 分词器名称
          "tokenizer": "ik_max_word",
          "filter": "pinyin"
        }
      }
     }
  }
}
# 不需要替换或者删除,就不加character filter了

再改下定义tokenizer filter时的各种属性:

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": { // 自定义分词器
        "my_analyzer": {  // 分词器名称
          "tokenizer": "ik_max_word",
          "filter": "py"
        }
      },
      "filter": { // 自定义tokenizer filter
        "py": { // 过滤器名称
          "type": "pinyin", // 过滤器类型,这里是pinyin
		  "keep_full_pinyin": false,  //解决全分为单个字的问题
          "keep_joined_full_pinyin": true,  //全拼
          "keep_original": true,  //是否保留中文
          "limit_first_letter_length": 16,
          "remove_duplicated_term": true,
          "none_chinese_pinyin_tokenize": false
        }
      }
    }
  }
}

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

测试下效果:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

插入两条name同音文档的后,搜索:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

但此时搜一下中文看看:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

很明显有问题,别人问狮子,你连同音词虱子都返回了。


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

创建倒排索引时,如下图:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

但当使用拼音分词器来搜索时:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

要解决这个问题,可以使用两个分词器:

"analyzer": "my_analyzer",   # 创建倒排索引时使用
"search_analyzer": "ik_smart" # 搜索时使用

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "ik_max_word", "filter": "py"
        }
      },
      "filter": {
        "py": { ... }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "my_analyzer",
        "search_analyzer": "ik_smart"  //!!!!
      }
    }
  }
}

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

重新测试下搜索中文的场景:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎
小结:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

3、completion suggester查询

ES提供Completion Suggester查询 来实现自动补全功能,该查询会匹配以用户输入内容开头的词条并返回。此时,文档中字段的类型也有特殊要求:

  • 参与补全查询的字段必须是completion类型。
  • 字段的内容一般是用来补全的多个词条形成的数组
// 创建索引库
PUT test
{
  "mappings": {
    "properties": {
      "title":{
        "type": "completion"   //注意字段类型为completion
      }
    }
  }
}

// 示例数据
POST test/_doc
{
  "title": ["Sony", "WH-1000XM3"]
}
POST test/_doc
{
  "title": ["SK-II", "PITERA"]
}
POST test/_doc
{
  "title": ["Nintendo", "switch"]
}

completion suggester查询语法:

// 自动补全查询
GET /test/_search
{
  "suggest": { //查询类型,用suggest 
    "title_suggest": { //给你的suggest查询起个名
      "text": "s", // 用户输入的关键字
      "completion": {
        "field": "title", // 补全查询的字段
        "skip_duplicates": true, // 跳过重复的
        "size": 10 // 获取前10条结果
      }
    }
  }
}

运行DSL:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

4、hotel索引库更新

看下之前的索引库的结构:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎
执行DSL来更新hotel索引库:

PUT /hotel
{
  "settings": {
    "analysis": {
      "analyzer": {
        "text_anlyzer": {  //定义第一个分词器
          "tokenizer": "ik_max_word",  //切割用ik_max
          "filter": "py"  //转换用拼音
        },
        "completion_analyzer": {   //定义第二个分词器,用于自动补全,不分词,直接转拼音
          "tokenizer": "keyword",  //分词用keyword,因为参与自动补全的是一个个词条,这些词条放在数组当中,本身就是个词条
          "filter": "py"
        }
      },
      "filter": {  //定义上面的拼音filter
        "py": {
          "type": "pinyin",
          "keep_full_pinyin": false,
          "keep_joined_full_pinyin": true,
          "keep_original": true,
          "limit_first_letter_length": 16,
          "remove_duplicated_term": true,
          "none_chinese_pinyin_tokenize": false
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "text_anlyzer",  //用来创建倒排索引时分词
        "search_analyzer": "ik_smart",  //用来全文检索
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword",
        "copy_to": "all"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "text_anlyzer",  //倒排索引分词
        "search_analyzer": "ik_smart"  //搜索分词
      },
      "suggestion":{   //新加这个字段,用来做自动补全
          "type": "completion",  //类型为completion
          "analyzer": "completion_analyzer"  //不分词,直接转拼音
      }
    }
  }
}

上面实现了:

  • 修改hotel索引库结构,设置自定义拼音分词器
  • 修改索引库的name、all字段,使用自定义分词器
  • 索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器

5、代码修改

上面索引库更新后,上一节中的代码也要发生修改:

  • 给HotelDoc类添加suggestion字段,内容包含brand、business
  • 重新导入数据到hotel库
//HotelDoc类修改
@Data
@NoArgsConstructor
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;
    //距离
    private Object distance;
    //是否充广告
    private Boolean isAD;
    //ES中的completion,后面存数组,这里可以对应成List
    private List<String> suggestion;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
        this.suggestion = Arrays.asList(this.brand,this.business);

    }
}

注意上面的Array.asList方法,使suggestion字段内容包含brand、business

//运行从MySQL读数据,插入文档到ES的单元测试代码
@SpringBootTest
public class HotelDocumentTest {

    @Resource
    IHotelService iHotelService;

    private RestHighLevelClient client;

    @Test
    void testInit(){

        System.out.println(client);
    }

    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://10.4.130.220:9200")
        ));
    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }


    @Test
    void testBulk() throws IOException {
        List<Hotel> hotels = iHotelService.list();
        BulkRequest request = new BulkRequest();
        for(Hotel hotel : hotels){
            HotelDoc hotelDoc = new HotelDoc(hotel);
            request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc),XContentType.JSON)
            );
        }
        client.bulk(request,RequestOptions.DEFAULT);



    }


}

查看下文档数据:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

在suggestion字段发现有数据的商业区有多个:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

修改下HotelDoc的有参构造,加判断逻辑,business字段有斜杠/时,分开后再放入suggestion

@Data
@NoArgsConstructor
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;
    //距离
    private Object distance;
    //是否充广告
    private Boolean isAD;
    //ES中的completion,后面存数组,这里可以对应成List
    private List<String> suggestion;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
        if(this.business.contains("/")){
            //此时business有多个值,需要分开后放入suggestion
            String[] arr = this.business.split("/");
            //添加元素
            this.suggestion = new ArrayList<>();
            Collections.addAll(this.suggestion,arr);
            this.suggestion.add(this.brand);
        }else{
            this.suggestion = Arrays.asList(this.brand,this.business);
        }

    }
}


重新运行单元测试,插入文档数据,可以看到切割完成了:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

执行自动补全查询的DSL,比如搜索h:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

6、RestAPI实现自动补全

Java代码对比DSL来看,查询的实现是:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

对响应结果的处理是:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

在单元测试中使用一下先:

@Test
    void testSuggest() throws IOException {
        //1、准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2、准备DSL
        request.source()
                .suggest(new SuggestBuilder().addSuggestion(
                        "mySuggestion",
                        SuggestBuilders.completionSuggestion("suggestion")
                                .prefix("h")  //搜索的关键字,这里用prefix,即前置,给方法起名很灵性
                                .skipDuplicates(true)
                                .size(10)
                ));
        //3、发起请求
        SearchResponse response = client.search(request,RequestOptions.DEFAULT);
        //4、解析结果
        Suggest suggest = response.getSuggest();
        //4.1 根据不全查询名称,获取查询结果
        CompletionSuggestion suggestion = suggest.getSuggestion("mySuggestion");
        //4.2 获取options
        List<CompletionSuggestion.Entry.Option> options = suggestion.getOptions();
        //4.3 遍历
        for (CompletionSuggestion.Entry.Option option : options) {
            String text = option.getText().toString();
            System.out.println(text);

        }
    }

运行得到以h开头的所有结果:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

7、需求:搜索框实现自动补全

看下前端页面,每当在输入框键入时,前端会发送ajax请求:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

接下来完善这个接口,实现搜索框的自动补全:

  • controller接口定义
import cn.itcast.hotel.domain.dto.RequestParams;
import cn.itcast.hotel.domain.vo.PageResult;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/hotel")
public class HotelSearchController {

    @Resource
    IHotelService hotelService;

    @GetMapping("/suggestion")
    public List<String> getSuggestions(@RequestParam("key") String prefix){
        return hotelService.getSuggestion(prefix);
    }



}
  • Service接口
public interface IHotelService extends IService<Hotel> {
 
    List<String> getSuggestion(String prefix);
}
  • 接口实现
@Override
public List<String> getSuggestion(String prefix) {
    try {
        SearchRequest request = new SearchRequest("hotel");
        request.source().suggest(new SuggestBuilder().addSuggestion(
                "mySuggestion",
                SuggestBuilders.completionSuggestion("suggestion")
                        .prefix(prefix)
                        .skipDuplicates(true)
                        .size(15)
        ));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        Suggest suggest = response.getSuggest();
        CompletionSuggestion mySuggestion = suggest.getSuggestion("mySuggestion");
        List<CompletionSuggestion.Entry.Option> options = mySuggestion.getOptions();
        return options.stream()
                .map(t -> t.getText().toString())
                .collect(Collectors.toList());
    } catch (IOException e) {
        throw new RuntimeException();
    }
}



  • 关于client这个Bean,再补充下:
@SpringBootApplication
public class HotelDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(HotelDemoApplication.class, args);
    }

    @Bean
    public RestHighLevelClient client(){
        return new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://10.4.130.220:9200")
        ));
    }

}

重启服务,看下效果:

【ElasticSearch】ES自动补全查询与Java接口实现,ElasticSearch,elasticsearch,大数据,搜索引擎

自动补全成功实现!!文章来源地址https://www.toymoban.com/news/detail-557260.html

到了这里,关于【ElasticSearch】ES自动补全查询与Java接口实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • elasticsearch(ES)分布式搜索引擎04——(数据聚合,自动补全,数据同步,ES集群)

    **聚合(aggregations)**可以让我们极其方便的实现对数据的统计、分析、运算。例如: 什么品牌的手机最受欢迎? 这些手机的平均价格、最高价格、最低价格? 这些手机每月的销售情况如何? 实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现近

    2024年02月08日
    浏览(40)
  • ElasticSearch进阶:多种查询操作,各种ES查询以及在Java中的实现

    目录 前言 1 词条查询 1.1 等值查询-term 1.2 多值查询-terms 1.3 范围查询-range 1.4 前缀查询-prefix 1.5 通配符查询-wildcard 2 复合查询 2.1 布尔查询 2.2 Filter查询 3 聚合查询 3.1 最值、平均值、求和 3.2 去重查询 3.3 分组聚合 3.3.1 单条件分组 3.3.2 多条件分组 3.4 过滤聚合 ElasticSearch 第一篇

    2024年02月02日
    浏览(44)
  • ES es Elasticsearch 十三 Java api 实现搜索 分页查询 复杂查询 过滤查询 ids查询 等

    目录 Java api 实现搜索 Pom.xml 建立链接 搜索全部记录 增加规则值查某些字段 搜索分页 全代码 Ids 搜索 搜索Match搜索 multi_match 搜索 多字段搜索 复杂查询 bool查询 filter  bool 复杂查询增加过滤器查询 复杂擦好像加排序 日志 思路 参考 api 写法 写Java代码 请求条件构建层次

    2024年02月04日
    浏览(50)
  • ElasticSearch进阶:一文全览各种ES查询在Java中的实现

    ElasticSearch进阶:一文全览各种ES查询在Java中的实现 es基本语句详解 查询语句详解 ElasticSearch第一篇: ElasticSearch基础:从倒排索引说起,快速认知ES 完整项目已上传至:ElasticSearch Demo 项目,该项目是关于springboot的集成项目,ElasticSearch部分请关注【elasticSearch-demo】模块。觉得

    2024年02月02日
    浏览(45)
  • Elasticsearch实现检索词自动补全(检索词补全,自动纠错,拼音补全,繁简转换) 包含demo

    下面的请求定义了一个名为 “book” 的 Elasticsearch 索引,其中包含一个 具有 “text” 数据类型和 “standard” 分析器且名为 “title” 的字段。此字段用于处理书籍标题的文本数据。定义了名为 “suggest” 的 “completion” 子字段,用于支持实时搜索建议的自动补全功能。 增加测

    2024年02月07日
    浏览(32)
  • 网页搜索自动补全功能如何实现,Elasticsearch来祝佬“一臂之力”

    前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章参考网上的课程,介绍Elasticsearch搜索引擎之自动补全功能的介绍与使用,这块内容不作为面试中的重点。 如果文章有什么需要改进的地方还请大佬不吝赐教 👏👏。 小威在此先感谢各位大佬啦~~🤞🤞

    2023年04月15日
    浏览(41)
  • ElasticSearch - 基于 拼音分词器 和 IK分词器 模拟实现“百度”搜索框自动补全功能

    目录 一、自动补全 1.1、效果说明 1.2、安装拼音分词器 1.3、自定义分词器 1.3.1、为什么要自定义分词器 1.3.2、分词器的构成 1.3.3、自定义分词器 1.3.4、面临的问题和解决办法 问题 解决方案 1.4、completion suggester 查询 1.4.1、基本概念和语法 1.4.2、示例 1.4.3、示例(黑马旅游)

    2024年02月07日
    浏览(41)
  • 【elasticsearch】ES去重查询实现

    去重实现原理: 采用es 的Collapse折叠+cardinality基数计算 实现去重 1、优点:简单快速效率高,几乎无性能损耗(相比于分桶去重) 2、缺点: 1)Collapse折叠只支持一个字段去重,且字段必须是 keyword 2)cardinality基数计算去重后数量 (采用hyperloglog实现,hyperloglog一种近似计算)

    2024年02月06日
    浏览(34)
  • java使用ElasticSearch的scroll查询,高效的解决es查询数量的限制。

    (1)首先我们要明白es的查询机制:ES的搜索是分2个阶段进行的,即 Query阶段和Fetch阶段 。 Query阶段 比较轻量级,通过查询倒排索引,获取满足查询结果的文档ID列表。 Fetch阶段 比较重,需要将每个分片的查询结果取回,在协调结点进行 全局 排序。 通过From+size这种方式分批

    2024年02月03日
    浏览(74)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包