精华内容
下载资源
问答
  • elasticsearch全文检索
    2021-12-29 22:29:53
    安装 pip install elasticsearch
    

    对于elasticsearch 5.x 版本 需要按以下方式导入

    from elasticsearch5 import Elasticsearch
    
    # elasticsearch集群服务器的地址
    ES = [
        '127.0.0.1:9200'
    ]
    
    # 创建elasticsearch客户端
    es = Elasticsearch(
        ES,
        # 启动前嗅探es集群服务器
        sniff_on_start=True,
        # es集群服务器结点连接异常时是否刷新es结点信息
        sniff_on_connection_fail=True,
        # 每60秒刷新结点信息
        sniffer_timeout=60
    )
    

    搜索使用方式

    query = {
        'query': {
            'bool': {
                'must': [
                    {'match': {'_all': 'python web'}}
                ],
                'filter': [
                    {'term': {'status': 2}}
                ]
            }
        }
    }
    ret = es.search(index='articles', doc_type='article', body=query)
    

    suggest查询

    1 拼写纠错

    对于已经建立的articles索引库,elasticsearch还提供了一种查询模式,suggest建议查询模式

    curl 127.0.0.1:9200/articles/article/_search?pretty -d '
    {
        "from": 0,
        "size": 10,
        "_source": false,
        "suggest": {
            "text": "phtyon web",
            "word-phrase": {
                "phrase": {
                    "field": "_all",
                    "size": 1
                }
            }
        }
    }'
    

    当我们输入错误的关键词phtyon web时,es可以提供根据索引库数据得出的正确拼写python web

    2 自动补全

    使用elasticsearch提供的自动补全功能,因为文档的类型映射要特殊设置,所以原先建立的文章索引库不能用于自动补全,需要再建立一个自动补全的索引库

    curl -X PUT 127.0.0.1:9200/completions -H 'Content-Type: application/json' -d'
    {
       "settings" : {
           "index": {
               "number_of_shards" : 3,
               "number_of_replicas" : 1
           }
       }
    }
    curl -X PUT 127.0.0.1:9200/completions -H 'Content-Type: application/json' -d'
    {
       "settings" : {
           "index": {
               "number_of_shards" : 3,
               "number_of_replicas" : 1
           }
       }
    }
    

    很简答理解:elasticsearch提供了两个建议查询,比如我想搜索python 结果我输入成了pyhton,elasticsearch会帮我们纠正,还有一种自动补全,比如我输入:python we 会帮我自动匹配,显而易见我想找python web

    更多相关内容
  • Elasticsearch全文搜索引擎 Elasticsearch全文搜索引擎
  • ElasticSearch实现全文检索

    千次阅读 2022-03-01 18:45:12
    搜索引擎服务使用 ElasticSearch 提供的对外 web 服务选则 Springboot web 1.1 ElasticSearch Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。...

    1、技术选型

    搜索引擎服务使用 ElasticSearch

    提供的对外 web 服务选则 Springboot web

    1.1 ElasticSearch

    Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
    官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

    现在开源的搜索引擎在市面上最常见的就是ElasticSearch和Solr,二者都是基于Lucene的实现,其中ElasticSearch相对更加重量级,在分布式环境表现也更好,二者的选则需考虑具体的业务场景和数据量级。对于数据量不大的情况下,完全需要使用像Lucene这样的搜索引擎服务,通过关系型数据库检索即可。

    1.2 Spring Boot

    现在 Spring Boot 在做 web 开发上是绝对的主流,其不仅仅是开发上的优势,在布署,运维各个方面都有着非常不错的表现,并且 Spring 生态圈的影响力太大了,可以找到各种成熟的解决方案。

    1.3 ik分词器

    ElasticSearch 本身不支持中文的分词,需要安装中文分词插件,如果需要做中文的信息检索,中文分词是基础,此处选则了ik,下载好后放入 elasticSearch 的安装位置的 plugin 目录即可。

    2、环境准备

    需要安装好elastiSearch以及kibana(可选),并且需要lk分词插件。

    1、安装elasticSearch elasticsearch官网. 笔者使用的是7.5.1。

    2、ik插件下载 ik插件github地址. 注意下载和你下载elasticsearch版本一样的ik插件。

    3、将ik插件放入elasticsearch安装目录下的plugins包下,新建报名ik,将下载好的插件解压到该目录下即可,启动es的时候会自动加载该插件。
    在这里插入图片描述

    3、项目架构

    1、获取数据使用ik分词插件

    2、将数据存储在es引擎中

    3、通过es检索方式对存储的数据进行检索

    4、使用es的java客户端提供外部服务
    在这里插入图片描述

    4、实现效果

    在这里插入图片描述

    5、具体代码实现

    5.1 全文检索的实现对象

    按照博文的基本信息定义了如下实体类,主要需要知道每一个博文的url,通过检索出来的文章具体查看要跳转到该url。

    package com.lbh.es.entity;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    
    import javax.persistence.*;
    
    /**
     * PUT articles
     * {
     * "mappings":
     * {"properties":{
     * "author":{"type":"text"},
     * "content":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_smart"},
     * "title":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_smart"},
     * "createDate":{"type":"date","format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"},
     * "url":{"type":"text"}
     * } },
     * "settings":{
     *     "index":{
     *       "number_of_shards":1,
     *       "number_of_replicas":2
     *     }
     *   }
     * }
     * ---------------------------------------------------------------------------------------------------------------------
     * Copyright(c)lbhbinhao@163.com
     * @author liubinhao
     * @date 2021/3/3
     */
    @Entity
    @Table(name = "es_article")
    public class ArticleEntity {
        @Id
        @JsonIgnore
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private long id;
        @Column(name = "author")
        private String author;
        @Column(name = "content",columnDefinition="TEXT")
        private String content;
        @Column(name = "title")
        private String title;
        @Column(name = "createDate")
        private String createDate;
        @Column(name = "url")
        private String url;
    
        public String getAuthor() {
            return author;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getCreateDate() {
            return createDate;
        }
    
        public void setCreateDate(String createDate) {
            this.createDate = createDate;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    }
    

    5.2 客户端配置

    通过java配置es的客户端

    /**
     * Copyright(c)lbhbinhao@163.com
     * @author liubinhao
     * @date 2021/3/3
     */
    @Configuration
    public class EsConfig {
    
        @Value("${elasticsearch.schema}")
        private String schema;
        @Value("${elasticsearch.address}")
        private String address;
        @Value("${elasticsearch.connectTimeout}")
        private int connectTimeout;
        @Value("${elasticsearch.socketTimeout}")
        private int socketTimeout;
        @Value("${elasticsearch.connectionRequestTimeout}")
        private int tryConnTimeout;
        @Value("${elasticsearch.maxConnectNum}")
        private int maxConnNum;
        @Value("${elasticsearch.maxConnectPerRoute}")
        private int maxConnectPerRoute;
    
        @Bean
        public RestHighLevelClient restHighLevelClient() {
            // 拆分地址
            List<HttpHost> hostLists = new ArrayList<>();
            String[] hostList = address.split(",");
            for (String addr : hostList) {
                String host = addr.split(":")[0];
                String port = addr.split(":")[1];
                hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
            }
            // 转换成 HttpHost 数组
            HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
            // 构建连接对象
            RestClientBuilder builder = RestClient.builder(httpHost);
            // 异步连接延时配置
            builder.setRequestConfigCallback(requestConfigBuilder -> {
                requestConfigBuilder.setConnectTimeout(connectTimeout);
                requestConfigBuilder.setSocketTimeout(socketTimeout);
                requestConfigBuilder.setConnectionRequestTimeout(tryConnTimeout);
                return requestConfigBuilder;
            });
            // 异步连接数配置
            builder.setHttpClientConfigCallback(httpClientBuilder -> {
                httpClientBuilder.setMaxConnTotal(maxConnNum);
                httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
                return httpClientBuilder;
            });
            return new RestHighLevelClient(builder);
        }
    
    }
    

    5.3 业务代码编写

    包括一些检索文章的信息,可以从文章标题,文章内容以及作者信息这些维度来查看相关信息。

    /**
     * Copyright(c)lbhbinhao@163.com
     * @author liubinhao
     * @date 2021/3/3
     */
    @Service
    public class ArticleService {
    
        private static final String ARTICLE_INDEX = "article";
    
        @Resource
        private RestHighLevelClient client;
        @Resource
        private ArticleRepository articleRepository;
    
        public boolean createIndexOfArticle(){
            Settings settings = Settings.builder()
                    .put("index.number_of_shards", 1)
                    .put("index.number_of_replicas", 1)
                    .build();
    // {"properties":{"author":{"type":"text"},
    // "content":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_smart"}
    // ,"title":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_smart"},
    // ,"createDate":{"type":"date","format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"}
    // }
            String mapping = "{\"properties\":{\"author\":{\"type\":\"text\"},\n" +
                    "\"content\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"}\n" +
                    ",\"title\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"}\n" +
                    ",\"createDate\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd\"}\n" +
                    "},\"url\":{\"type\":\"text\"}\n" +
                    "}";
            CreateIndexRequest indexRequest = new CreateIndexRequest(ARTICLE_INDEX)
                    .settings(settings).mapping(mapping,XContentType.JSON);
            CreateIndexResponse response = null;
            try {
                response = client.indices().create(indexRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (response!=null) {
                System.err.println(response.isAcknowledged() ? "success" : "default");
                return response.isAcknowledged();
            } else {
                return false;
            }
        }
    
        public boolean deleteArticle(){
            DeleteIndexRequest request = new DeleteIndexRequest(ARTICLE_INDEX);
            try {
                AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
                return response.isAcknowledged();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        public IndexResponse addArticle(ArticleEntity article){
            Gson gson = new Gson();
            String s = gson.toJson(article);
            //创建索引创建对象
            IndexRequest indexRequest = new IndexRequest(ARTICLE_INDEX);
            //文档内容
            indexRequest.source(s,XContentType.JSON);
            //通过client进行http的请求
            IndexResponse re = null;
            try {
                re = client.index(indexRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return re;
        }
    
        public void transferFromMysql(){
            articleRepository.findAll().forEach(this::addArticle);
        }
    
        public List<ArticleEntity> queryByKey(String keyword){
            SearchRequest request = new SearchRequest();
            /*
             * 创建  搜索内容参数设置对象:SearchSourceBuilder
             * 相对于matchQuery,multiMatchQuery针对的是多个fi eld,也就是说,当multiMatchQuery中,fieldNames参数只有一个时,其作用与matchQuery相当;
             * 而当fieldNames有多个参数时,如field1和field2,那查询的结果中,要么field1中包含text,要么field2中包含text。
             */
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    
            searchSourceBuilder.query(QueryBuilders
                    .multiMatchQuery(keyword, "author","content","title"));
            request.source(searchSourceBuilder);
            List<ArticleEntity> result = new ArrayList<>();
            try {
                SearchResponse search = client.search(request, RequestOptions.DEFAULT);
                for (SearchHit hit:search.getHits()){
                    Map<String, Object> map = hit.getSourceAsMap();
                    ArticleEntity item = new ArticleEntity();
                    item.setAuthor((String) map.get("author"));
                    item.setContent((String) map.get("content"));
                    item.setTitle((String) map.get("title"));
                    item.setUrl((String) map.get("url"));
                    result.add(item);
                }
                return result;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public ArticleEntity queryById(String indexId){
            GetRequest request = new GetRequest(ARTICLE_INDEX, indexId);
            GetResponse response = null;
            try {
                response = client.get(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (response!=null&&response.isExists()){
                Gson gson = new Gson();
                return gson.fromJson(response.getSourceAsString(),ArticleEntity.class);
            }
            return null;
        }
    }
    

    5.4 对外接口

    和使用springboot开发web程序相同。

    /**
     * Copyright(c)lbhbinhao@163.com
     * @author liubinhao
     * @date 2021/3/3
     */
    @RestController
    @RequestMapping("article")
    public class ArticleController {
    
        @Resource
        private ArticleService articleService;
    
        @GetMapping("/create")
        public boolean create(){
            return articleService.createIndexOfArticle();
        }
    
        @GetMapping("/delete")
        public boolean delete() {
            return articleService.deleteArticle();
        }
    
        @PostMapping("/add")
        public IndexResponse add(@RequestBody ArticleEntity article){
            return articleService.addArticle(article);
        }
    
        @GetMapping("/fransfer")
        public String transfer(){
            articleService.transferFromMysql();
            return "successful";
        }
    
        @GetMapping("/query")
        public List<ArticleEntity> query(String keyword){
            return articleService.queryByKey(keyword);
        }
    }
    

    5.5 页面

    此处页面使用thymeleaf,主要原因是笔者真滴不会前端,只懂一丢丢简单的h5,就随便做了一个可以展示的页面。

    搜索页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>YiyiDu</title>
        <!--
            input:focus设定当输入框被点击时,出现蓝色外边框
            text-indent: 11px;和padding-left: 11px;设定输入的字符的起始位置与左边框的距离
        -->
        <style>
            input:focus {
                border: 2px solid rgb(62, 88, 206);
            }
            input {
                text-indent: 11px;
                padding-left: 11px;
                font-size: 16px;
            }
    </style>
        <!--input初始状态-->
        <style class="input/css">
            .input {
                width: 33%;
                height: 45px;
                vertical-align: top;
                box-sizing: border-box;
                border: 2px solid rgb(207, 205, 205);
                border-right: 2px solid rgb(62, 88, 206);
                border-bottom-left-radius: 10px;
                border-top-left-radius: 10px;
                outline: none;
                margin: 0;
                display: inline-block;
                background: url(/static/img/camera.jpg) no-repeat 0 0;
                background-position: 565px 7px;
                background-size: 28px;
                padding-right: 49px;
                padding-top: 10px;
                padding-bottom: 10px;
                line-height: 16px;
            }
    </style>
        <!--button初始状态-->
        <style class="button/css">
            .button {
                height: 45px;
                width: 130px;
                vertical-align: middle;
                text-indent: -8px;
                padding-left: -8px;
                background-color: rgb(62, 88, 206);
                color: white;
                font-size: 18px;
                outline: none;
                border: none;
                border-bottom-right-radius: 10px;
                border-top-right-radius: 10px;
                margin: 0;
                padding: 0;
            }
    </style>
    </head>
    <body>
    <!--包含table的div-->
    <!--包含input和button的div-->
        <div style="font-size: 0px;">
            <div align="center" style="margin-top: 0px;">
                <img src="../static/img/yyd.png" th:src = "@{/static/img/yyd.png}"  alt="一亿度" width="280px" class="pic" />
            </div>
            <div align="center">
                <!--action实现跳转-->
                <form action="/home/query">
                    <input type="text" class="input" name="keyword" />
                    <input type="submit" class="button" value="一亿度下" />
                </form>
            </div>
        </div>
    </body>
    </html>
    

    搜索结果页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
        <meta charset="UTF-8">
        <title>xx-manager</title>
    </head>
    <body>
    <header th:replace="search.html"></header>
    <div class="container my-2">
        <ul th:each="article : ${articles}">
            <a th:href="${article.url}"><li th:text="${article.author}+${article.content}"></li></a>
        </ul>
    </div>
    <footer th:replace="footer.html"></footer>
    </body>
    </html>
    

    整体思路解析:
    当用户输入关键词搜索时,首先使用ik分词器分词把数据存储在es客户端中,通过业务的代码来对数据进行检索,检索到了数据,通过对外接口返回给界面,向用户展示搜索的结果,就是按图开发代码。

    展开全文
  • Elasticsearch全文检索

    2020-09-18 11:39:40
    Elasticsearch全文检索,springboot整合ES,包括创建索引,根据id查询,关键字查询,删除索引等基本操作。
  • Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下...
  • 课程提供所有代码笔记素材...2、ElasticSearch下载安装(window以及linux下安装) 3、集群环境搭建 4、客户端Kibana安装与使用 5、集群管理插件head安装使用 6、java api 操作 ES 7、电商项目实战应用等等 .....
  • ElasticSearch 是一个分布式、可扩展、高性能的检索与数据分析引擎...ElasticSearch 基于 Java 编写,通过对Lucene进一步封装 ,将搜索的复杂性屏蔽起来,开发者只需要一套简单的 RESTful API 就可以操作全文检索。...

    ElasticSearch 是一个分布式、可扩展、高性能的检索与数据分析引擎。ElasticSearch 基于 Java 编写,通过对Lucene进一步封装 ,将搜索的复杂性屏蔽起来,开发者只需要一套简单的 RESTful API 就可以操作全文检索。

    1、windows环境es单节点安装
    下载地址https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-9-3
    下载后到指定目录解压即可,解压后的目录如下
    在这里插入图片描述
    进入bin目录,双击elasticsearch.bat启动即可。
    在这里插入图片描述
    看到started即启动成功。
    默认监听的端口是9200,访问如下
    在这里插入图片描述
    浏览器安装插件,在chrome的app store中搜索Elasticsearch-head,点击安装即可。
    在chrome 浏览器中,通过“扩展程序” 添加 elasticsearch head 插件的方式,这种方式无须开启 es的跨域访问,并提供了一个可操作es的图形化界面。
    打开连接http://extb.cqttech.com/search/elasticsearch%2520head,点击安装,如下
    在这里插入图片描述
    访问的可视化界面如下
    在这里插入图片描述
    2、windows环境kibana安装
    Kibana 是一个 Elastic 公司推出的一个针对 es 的分析及数据可视化平台,可以搜索、查看存放在 es 中的数据。

    • 下载地址:https://www.elastic.co/cn/downloads/kibana
    • 解压
    • 配置 es 的地址信息:若 es 是默认地址以及端口,可以不用配置,具体的配置文件是config/kibana.yml
    • 启动:双击kibana.bat即可
    • 访问localhost:5601
      界面如下
      在这里插入图片描述
      在这里插入图片描述
      Kibana 安装好之后,首次打开时,可以选择初始化 es 提供的测试数据,也可以不使用。

    3、分词器
    ElasticSearch 中内置了多种分词器,如Standard Analyzer:标准分词器,适用于英语等;其中中文分词器通常使用elasticsearch-analysis-ik,这个是第三方插件,下载地址如下:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.9.3
    下载后在es的plugins目录下,新建ik目录,并将解压后的所有文件拷贝到ik目录下,重启es服务。
    注:es和kibana的安装路径不能有空格,否则启动会报错。
    es重启成功后,首先创建一个名为test的索引(相当于是创建一个名为test的数据库),如下
    在这里插入图片描述
    在test索引中进行分词测试,如下
    在这里插入图片描述
    4、新建文档
    创建索引后,向索引中添加一个文档,如下
    在这里插入图片描述

    • _index表示文档索引
    • _type表示文档类型
    • _id表示文档id
    • _version表示文档版本
    • result表示执行的结果
    • _shards表示分片信息
    • _seq_no和_primary_term表示是版本控制用的
      添加文档成功后,通过浏览器插件可以看到如下
      在这里插入图片描述
      5、获取文档
      es中提供了GET API来查看es中的文档,如下
      在这里插入图片描述
      若获取的文档不存在,会返回如下
      在这里插入图片描述
      更新整个文档,如下
      在这里插入图片描述
      6、搜索
      创建索引,如下
      在这里插入图片描述
      查询文档,如下
      在这里插入图片描述
      添加文档
      在这里插入图片描述
      查询文档
      在这里插入图片描述
      或简单查询
      在这里插入图片描述
      词项查询,根据词去查询,查询指定字段中包含给定单词的文档,如下
      在这里插入图片描述
      7、全文检索
      在这里插入图片描述
      match query 会对查询语句进行分词,分此后如果查询语句中的任何一个词项被匹配,则文档就会被索引到。
      全文检索还有 match_phrase query、multi_match query、query_string query等,还有各种复杂的组合查询等,还需不断的尝试理解。

    8、实例
    pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.ldc</groupId>
        <artifactId>springboot_elasticsearch</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot_elasticsearch</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    application.properties文件

    elasticsearch.host=127.0.0.1
    elasticsearch.port=9200
    

    es配置类

    @Configuration
    @Data
    public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
    
        @Value("${elasticsearch.host}")
        private String host ;
        @Value("${elasticsearch.port}")
        private Integer port ;
    
        @Override
        public RestHighLevelClient elasticsearchClient() {
            RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
            RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
            return restHighLevelClient;
        }
    }
    

    索引库实体类

    @Data
    @Document(indexName = "blog_index", type = "blog")
    public class EsBlog {
    
        @Id
        private int id;
    
        /**
         * 是否索引: 看该域是否能被搜索, index = true(默认为true)
         * 是否分词: 表示搜索的时候是整体匹配还是单词匹配
         * 是否存储: 是否在页面上显示
         */
        @Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")
        private String title;
    
        @Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")
        private String content;
    
        public EsBlog() {
        }
    
        public EsBlog(int id, String title, String content) {
            this.id = id;
            this.title = title;
            this.content = content;
        }
    }
    

    es持久化

    @Repository
    public interface EsBlogRepository extends ElasticsearchRepository<EsBlog, Integer> {
        /**
         * 根据title或者内容分页查询
         *
         * @param title   标题
         * @param content 内容
         * @param page    分页
         * @return
         */
        Page<EsBlog> findByTitleOrContentLike(String title, String content, Pageable page);
    }
    

    es服务

    @Service
    public class EsBlogServiceImpl implements EsBlogService {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Resource
        private EsBlogRepository esBlogRepository;
    
        @Resource
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Override
        public void save(EsBlog blog) {
            esBlogRepository.save(blog);
            logger.debug("save ok");
        }
        @Override
        public void save(List<EsBlog> blogs) {
            esBlogRepository.saveAll(blogs);
            logger.debug("save ok");
        }
    
        @Override
        public void delete(int id) {
            esBlogRepository.deleteById(id);
        }
    
        @Override
        public EsBlog getById(int id) {
            EsBlog esBlog = esBlogRepository.findById(id).orElse(new EsBlog());
            logger.debug(esBlog.toString());
            return esBlog;
    
        }
    
        @Override
        public Page<EsBlog> getByKey(String key, Pageable pageable) {
            if(StringUtils.isEmpty(key)){
                return esBlogRepository.findAll(pageable);
            }
            return esBlogRepository.findByTitleOrContentLike(key, key, pageable);
        }
    
        @Override
        public Page<EsBlog> getByKeyWord(String key, Pageable pageable) {
            if(StringUtils.isEmpty(key)){
                System.out.println("key is null");
            }
            SearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(matchQuery("title", key))
                    .withQuery(matchQuery("content", key))
                    .withPageable(pageable)
                    .build();
            Page<EsBlog> esBlogs = elasticsearchRestTemplate.queryForPage(searchQuery, EsBlog.class);
            esBlogs.forEach(e -> logger.debug(e.toString()));
            return esBlogs;
        }
    }
    

    es接口

    @RestController
    @RequestMapping("blog")
    public class EsBlogController {
    
        @Resource
        private EsBlogService searchService;
    
        @GetMapping("init")
        private String initBlog() {
            List<Blog> blogs = new ArrayList<>();
            blogs.add(new Blog(1, "java", "java编程语言"));
            blogs.add(new Blog(2, "netty", "netty编程"));
            List<EsBlog> esBlogs = new ArrayList<>();
            blogs.forEach(blog -> {esBlogs.add(new EsBlog(blog.getId(), blog.getTitle(), blog.getContent()));});
            searchService.save(esBlogs);
            return "init Success";
        }
    
        /**
         * @param blog 博客文档
         * @return
         */
        @PostMapping("save")
        public void save(EsBlog blog) {
            searchService.save(blog);
        }
    
        /**
         * @param id 文档id
         * @return
         */
        @GetMapping("getById")
        public Object getById(int id) {
            return searchService.getById(id);
        }
    
        /**
         * @param key 关键字
         * @return
         */
        @GetMapping("getByKey")
        public Page<EsBlog> getByKey(HttpServletRequest request, String key) {
            Pageable pageable = getPageByRequest(request);
            return searchService.getByKey(key, pageable);
        }
    
        /**
         * @param key 关键字
         * @return
         */
        @GetMapping("getByKeyWord")
        public Page<EsBlog> getByKeyWord(HttpServletRequest request, String key) {
            Pageable pageable = getPageByRequest(request);
            return searchService.getByKeyWord(key, pageable);
        }
    
        private Pageable getPageByRequest(HttpServletRequest request) {
            int page = StringUtils.isEmpty(request.getParameter("page")) ? 1 : Integer.parseInt(request.getParameter("page"));
            int size = StringUtils.isEmpty(request.getParameter("size")) ? 10 : Integer.parseInt(request.getParameter("size"));
            Pageable pageable = PageRequest.of(page - 1, size);
            return pageable;
        }
    }
    

    检索示例如下
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 全文检索一般是查询包含某一或某些关键字记录,所以通过文档整体值建立的索引对提高查询速度是没有任何帮助的。为了解决这个问题,人们创建了一种新索引方法,这种索引方法就是倒排索引。

    在这里插入图片描述

    1.从全文检索说起

    首先介绍一下结构化与非结构化数据:

    • 结构化数据将数据具有的特征事先以结构化的形式定义好,数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构,数据特征直接体现在表结构的字段上,所以根据某一特征做数据检索很直接,速度也比较快
    • 非结构化数据没有预先定义好的结构化特征,也没有固定格式和固定长度。典型的非结构化数据包括文章、图片、视频、网页、邮件等,其中像HTML网页这种具有一定格式的文档也称为半结构化数据

    对于非结构化的数据检索,被称为全文检索。

    假设现在MySQL中有一张User表,含有三个阶段:姓名name、年龄age和爱好favor:
    在这里插入图片描述

    对于User表来说,整体上是结构化的,比如name、age都可以直接建立索引来快速地检索。
    而其中的favor字段是一个text类型,存储的是非结构化的文本数据:

    篮球、足球、爱运动的我;本人热爱学习,游戏偶尔也玩!!!!
    

    与结构化查询相比,全文检索面临的最大问题就是性能问题。全文检索最一般的应用场景是根据一些关键字查找包含这些关键字的文档,比如互联网搜索引擎要实现的功能就是根据一些关键字查找网页。显然,如果没有对文档做特别处理,查找的办法似乎只能是逐条比对。

    假设现在需要找到favor中含有“足球”这个关键字的User,那么只能使用like模糊查询:

    select * from user where favor like '%足球%'
    

    like语句是无法建立索引的,查询时会进行全表扫描,并且在每个favor字段中进行遍历匹配,以找到含有“足球”这个关键字的记录,整体复杂度特别高,所以全文检索也是MySQL这类结构关系式数据库无法很好实现的需求。

    全文检索一般是查询包含某一或某些关键字记录,所以通过文档整体值建立的索引对提高查询速度是没有任何帮助的。为了解决这个问题,人们创建了一种新索引方法,这种索引方法就是倒排索引。

    2.倒排索引的原理

    倒排索引是为了解决上述非结构化数据的检索问题而产生的。

    首先明确一下,在ES中存储记录的单位是JSON“文档”,而JSON“文档”中的“字段”也就是组成JSON的一个个KV对。

    普通索引也被称为正排索引,也就是通过对主键和结构化字段建立索引,通过这些结构化索引找到文档。

    倒排索引则是先将文档中包含的关键字全部提取出来,然后再将关键字与文档的对应关系保存起来,最后再对关键字本身做索引排序。用户在检索某一关键字时,可以先对关键字的索引进行查找,再通过关键字与文档的对应关系找到所在文档。

    假设上述的User表通过ES存储,其中两个User文档为:

    {
        "_id: 1,
        "name":"pbr1",
        "age":22,
        "favor":"篮球、足球、爱运动的我;本人热爱学习,游戏偶尔也玩!!!!"
    }
    
    {
        "_id: 2,
        "name":"pbr2",
        "age":22,
        "favor":"篮球、足球、爱运动的我"
    }
    

    其中favor定义为text类型,假设分词器进行以下分词:

    • 文档1的favor分词:“篮球”、“足球”、“爱运动的我”、“本人热爱学习”、“游戏偶尔也玩”这5个token
    • 文档2的favor分词:“篮球”、“足球”、“爱运动的我”这3个token

    那么对分词token建立索引,并建立对原始文档的映射,就得到一个以favor进行分词的倒排索引:
    在这里插入图片描述

    可以看到,倒排索引实际上就是对全文数据结构化的过程。对于存储在关系型数据库中的数据来说,它们依赖于人的预先分析将数据拆解为不同字段,所以在数据插入时就已经是结构化的;而在全文数据库中,文档在插入时还不是结构化的,需要应用程序根据规则自动提取关键字,并形成关键字与文档之间的结构化对应关系。

    比如现在需要查询爱好为“篮球”和“足球”的用户,那么可以直接通过倒排索引拿到对应的文档1和文档2,也就查询到了这两个用户。

    3.ES索引构建过程

    全文检索中提取关键字是非常重要的一步。这些预先提取出来的关键字,在Elasticsearch及全文检索的相关文献中一般称为词项(Term),文档的词项提取在Elasticsearch中称为文档分析(Analysis),是整个全文检索中较为核心的过程。这个过程必须要区分哪些是词项,哪些不是。对于英文来说,它还必须要知道apple和apples指的同一个东西,而run和running指的是同一动作。对于中文来说就更麻烦了,因为中文词语不以空格分隔,所以面临的第一难题是如何将词语分辨出来。

    ES底层使用了Lucene来构建索引,一个基本的过程是先对text类型的字段进行分词,分词使用的分词器以配置mapping时指定的为准,默认使用standard分词器,对于中文分词来说,一般建议使用ik_smart或ik_max_word分词器:

    在这里插入图片描述

    关于Lucene如何存储这些分词解析结果可以学习这篇文章:https://www.shenyanchao.cn/blog/2018/12/04/lucene-index-files/

    由于文档存储前的分析和索引过程比较耗资源,所以为了提升性能,文档在添加到ES中时并不会立即被编入索引。

    默认情况下,ES会每隔1s统一处理一次新加入的文档,可以通过index.refresh_interval参数修改。

    为了提升性能,在ES 7中还添加了index.search.idle.after参数,它的默认值是30s:如果索引在一段时间内没有收到检索数据的请求,那么它至少要等30s后才会刷新索引数据。

    所以可以看出ES的写入操作实际上是准实时的,新添加到索引中的文档可能在一段时间内不能被检索到,如果的确需要立即检索到文档可以使用强制刷新到索引的方式,包括使用_refresh接口和在操作文档时使用refresh参数等进行强制刷新缓冲区中的索引到磁盘中。

    展开全文
  • 全文检索ElasticSearch(一篇就够了)

    千次阅读 2021-12-08 07:47:47
    Elaticsearch简称为ES,是一个开源的可扩展的分布式的全文检索引擎,它可以近乎实时的存储、检索数据。本身扩展性很好,可扩展到上百台服务器,处理PB级别的数据。 ES使用Java开发并使用Lucene作为其核心来实现索引和...
  • elasticsearch全文搜索

    2018-08-23 16:37:14
    ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索...
  • 全文搜索引擎 Elasticsearch详解

    千次阅读 2022-03-28 10:44:56
    Elasticsearch 是一个分布式的免费开源搜索和分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V....
  • 下载elasticsearch文件 官网下载地址:https://www.elastic.co/downloads/elasticsearch 其他网址: ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D logstash: ...
  • 为什么要写这个系列的文章呢,基于两个原因,一是在为企业招人的时候发现很多是工作多年的求职者都还没有接触过全文检索引擎,二是应朋友请求希望我写一写ElasticSearch(简称ES)的技术文章,该系列文章将分为如下几...
  • ElasticSearch 基本原理之全文检索

    千次阅读 2020-11-01 14:39:14
    MySQL:通过分库分表可以存海量数据,但是做数据检索效率是达不到毫秒级别,并且数据检索只能支持模糊查询,不支持全文检索、分词检索 以上数据库都可以做海量数据存储,但都不适合做检索的工作。 2)如何解决单点...
  • 全文检索服务 _ ElasticSearch

    千次阅读 2021-11-10 16:18:48
    Elasticsearch是一个全文检索服务器 1 全文检索 全文检索是一种非结构化数据的搜索方式。 结构化数据:指具有固定格式固定长度的数据,如数据库中的字段。 非结构化数据:指格式和长度不固定的数据,如电商网站的...
  • SpringBoot+ElasticSearch 实现全文检索

    千次阅读 2020-12-03 00:01:25
    SpringBoot集成ElasticSearch实战 一、在pom.xml中引入依赖 <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-elasticsearch --> <dependency> <gro
  • ElasticSearch作为基于Lucene的搜索服务器,既可以...SpringBoot作为Spring家族的全新框架,使得使用SpringBoot开发Spring应用变得非常简单,在本案例中我们给大家介绍Spring Boot整合Elasticsearch实现全文搜索引擎
  • ElasticSearch全文检索(一) 为什么要用ElasticSearch?它可以解决什么问题? 中文文档:使用聚合分析结果 (bookhub.zone) https://www.elastic.co/cn/elasticsearch/ 先讲一下什么是Elasticsearch。 简单说,...
  • 前言 今天开始我们学习如何使用Java来操作ES,这里会讲两种操作方式,一是使用ES提供的jar包来操作,二是使用SpringBootData来操作,第二种方式是企业里面使用的较多的方式了。
  • Spring和Elasticsearch全文搜索整合详解

    千次阅读 2019-07-10 11:20:58
    Spring和Elasticsearch全文搜索整合详解 一、概述 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可...
  • elasticsearch一个准实时的搜索引擎,基于lucene构建,它的主要强项还是在全文检索方面。工作中还是使用到了这部分功能,这里做一个简单的总结,可以使初次使用的人很快的配置和使用。一、全文检索的概念 首先介绍...
  • SpringBoot集成Elasticsearch实现全文搜索学习ElasticsearchElasticsearch下载安装功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建...
  • 题记学习ES的童鞋,都有一个开发一个类似百度的搜索引擎的想法。...1、Elasticsearch全文检索系统效果图注:这张图是从网上down的,我已经实现了上述功能。 (不能截图,原因:你懂的!)2、Elasticsearch全文检索系...
  • /*** es全文检索java实现API* @author zxy**/public class EsPersonDao {/**** @param index 查询的索引* @param str 查询内容* @param Page 页码* @param Pagesize 每页显示条数* @return SearchHits, json结构的...
  • ElasticSearch-Java Client类型Node Client1) 客户端节点本身也是ElasticSearch节点2)也进入集群,和其他ElasticSearch节点一样3)升级维护麻烦(词库、配置等等)...
  • Elasticsearch本质是一个java语言开发的web项目,我们可以通 过RESTful风格的接口访问该项目内部的Lucene,从而让全文搜索变得简单。 2. 正排索引&倒排索引 索引:将数据中的一部分信息提取出来,重新组织成...
  • 全文检索 Elasticsearch(简称es)

    千次阅读 2019-06-04 23:51:28
    全文检索 Elasticsearch 研究 1. ElasticSearch 介绍 1.1 介绍 **Elasticsearch**是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档。Elasticsearch...
  • ES全文检索基本招式

    2021-03-16 16:12:06
    一、match在执行match查询时,默认情况下,字段值必须匹配任意一个词条,比如文档的eventname字段匹配任意一个分词,azure、aws和cloud时,该文档就匹配POST /_search -d{"from":10,"size":5,"query":{"match":{...
  • 2. 全文检索引擎 ElasticSearch;3. 安装 ElasticSearch 以及中文分词插件 IK;3.1 安装 ElasticSearch7;3.2 安装 elasticsearch-head;3.3 ElasticSearch 设置密码;3.4 安装中文分词插件 IK;4. 创建索引;5. ...
  • 全文搜索属于最常见的需求,开源的 Elasticsearch 是目前全文搜索引擎的首选。它可以快速地存储、搜索和分析海量数据。 维基百科、Stack Overflow、Github 都采用它。 Elastic 的底层是开源库 Lucene。 但是,你没法...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 187,025
精华内容 74,810
关键字:

elasticsearch全文检索