专栏首页Hcode网站Spring Boot(三)集成ElasticSearch

Spring Boot(三)集成ElasticSearch

概述

Elaticsearch简称为es, es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。es也使用 Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。 据国际权威的数据库产品评测机构DB Engines的统计,在2016年1月,ElasticSearch已超过Solr等,成 为排名第一的搜索引擎类应用。 ElasticSearch运用在哪?

  1. 维基百科,类似百度百科,全文检索,高亮,搜索推荐(权重,百度!)
  2. The Guardian(国外新闻网站),类似搜狐新闻,用户行为日志(点击,浏览,收藏,评论)+社交 网络数据(对某某新闻的相关看法),数据分析,给到每篇新闻文章的作者,让他知道他的文章的公众 反馈(好,坏,热门,垃圾,鄙视,崇拜)
  3. Stack Overflow(国外的程序异常讨论论坛),IT问题,程序的报错,提交上去,有人会跟你讨论和 回答,全文检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到里面去,搜索有没有对应 的答案
  4. GitHub(开源代码管理),搜索上千亿行代码
  5. 电商网站,检索商品
  6. 日志数据分析,logstash采集日志,ES进行复杂的数据分析,ELK技术, elasticsearch+logstash+kibana
  7. 商品价格监控网站,用户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给用户,比如 说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于50块钱,就通知我,我就去买。
  8. BI系统,商业智能,Business Intelligence。比如说有个大型商场集团,BI,分析一下某某区域近 3年的用户消费金额的趋势以及用户群体的组成构成,产出相关的数张报表,**区,近3年,每年消费 金额呈现100%的增长,而且用户群体85%是高级白领,开一个新商场。ES执行数据分析和挖掘, Kibana进行数据可视化
  9. 国内:站内搜索(电商,招聘,门户,等等),IT系统搜索(OA,CRM,ERP,等等),数据分析 (ES热门的使用)

ELK是什么

ELK是Elasticsearch、Logstash、Kibana三大开源框架首字母大写简称。市面上也被成为Elastic Stack。其中Elasticsearch是一个基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框 架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用Elasticsearch作为底层支持框架,可 见Elasticsearch提供的搜索能力确实强大,市面上很多时候我们简称Elasticsearch为es。Logstash是ELK 的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后支持输出 到不同目的地(文件/MQ/redis/elasticsearch/kafka等)。Kibana可以将elasticsearch的数据通过友好 的页面展示出来,提供实时分析的功能。 市面上很多开发只要提到ELK能够一致说出它是一个日志分析架构技术栈总称,但实际上ELK不仅仅适用 于日志分析,它还可以支持其它任何数据分析和收集的场景,日志分析和收集只是更具有代表性。并非 唯一性。

ES核心概念

  • 索引
  • 字段类型
  • 文档

elasticsearch是面向文档,关系型数据库 和 elasticsearch 客观的对比!一切都是JSON! 看看下方对比!

elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包 含多 个文档(行),每个文档中又包含多个字段(列)。

文档

一个文档其实相当于数据库表中一行的数据。

elasticsearch是面向文档的,那么就意味着索引和搜索数据的小单位是文档.

elasticsearch 中,文档有几个 重要属性 : - 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含 key:value - 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的! {就是一个json对象! fastjson进行自动转换!} - 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用, 在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个 新的字段。

类型

类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。 类型中对于字段的定义称为映射, 比如 name 映 射为字符串类型。 我们说文档是无模式的,它们不需要拥有映射中所定义的所有字段, 比如新增一个字段,那么elasticsearch是怎么做的呢?elasticsearch会自动的将新字段加入映射,但是这 个字段的不确定它是什么类型,elasticsearch就开始猜,如果这个值是18,那么elasticsearch会认为它 是整形。 但是!!!最好自己定义类型,不然可能会出错!!!

索引

索引相当于数据库! 索引是映射类型的容器,elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段 和其他设置。 然后它们被存储到了各个分片上了。 我们来研究下分片是如何工作的。

分片

一个集群至少有一个节点,而一个节点就是一个elasricsearch进程,节点可以有多个索引默认的,如果 你创建索引,那么索引将会有个5个分片 ( primary shard ,又称主分片 ) 构成的,每一个主分片会有一个 副本 ( replica shard ,又称复制分片 )

主分片和复制分片会存放在不同的节点,一个分片是一个Lucene索引,一个包含倒排索引的文件 目录,倒排索引的结构使 得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的 关键字。

倒排索引

也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。

集成到Spring Boot

此为原生依赖

注意:elasticsearch的依赖需要与下载的ES版本一致,本次使用的7.6.2的!!!

COPY<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

不过在SpringBoot中无需如此,直接导入

COPY    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>

也有最简单的方式,在创建SpringBoot项目时直接勾选依赖组件。

导入后的项目依赖pom.xml文件为如下,同学顺便导入jackJson方便传输数据!!

COPY<?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.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>top.hcode</groupId>
    <artifactId>hcode-es-api-1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hcode-es-api-1</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <!--自定义依赖版本-->
        <elasticsearch.version>7.6.2</elasticsearch.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

然后编写配置文件,注入到Spring容器中

COPY@Configuration
public class ElasticSearchClientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        return new RestHighLevelClient(
                RestClient.builder(
                    //有几个集群写几个!!
                        new HttpHost("127.0.0.1",,"http"),
                        new HttpHost("127.0.0.1",,"http")
                )
        );
    }
}

SpringBoot中使用ES

注入RestHighLevelClient

COPY    @Autowired
    private RestHighLevelClient restHighLevelClient;

创建索引

COPY   void createIndex() throws IOException {
        //创建索引请求
        CreateIndexRequest index = new CreateIndexRequest("hcode_index"); //hcode_index为索引名
        //执行请求,获得响应
        CreateIndexResponse response = restHighLevelClient.indices().create(index, RequestOptions.DEFAULT);

        System.out.println(response);
    }

判断索引是否存在

COPY    void ExistIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("hcode_index");
        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

删除索引

COPYvoid DeleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("hcode_index");
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged()); //为true表示删除成功
    }

添加文档

COPYvoid AddDocument() throws IOException {
        User user = new User("hcode", );
        //创建索引请求
        IndexRequest request = new IndexRequest("hcode_index");
        //设置规则 例如相当于 PUT /hcode_index/_doc/1 命令
        request.id("1").timeout(TimeValue.timeValueSeconds());//设置id,1秒超时
        request.timeout("1s");

        // 数据转换成json 放入请求
        request.source(JSON.toJSONString(user), XContentType.JSON);

        //将请求发出去,获取响应结果
        IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);

        System.out.println(indexResponse.status()); // 返回当前操作的类型:CREATE
        System.out.println(indexResponse.toString()); //响应内容

    }

判断文档是否存在

COPYvoid IsExists() throws IOException {
        GetRequest getRequest = new GetRequest("hcode_index", "1");
        // 不获取返回的_source 的上下文,会提高速度
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");

        boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

获取文档的信息 GET /hcode_index/_doc/1

COPY//相当于  GET /hcode_index/_doc/1
 void getDocument() throws IOException {
        GetRequest getRequest = new GetRequest("hcode_index", "1");

        GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);

        System.out.println(response.getSourceAsString()); //获取文档的内容
    }

更新文档信息

COPYvoid updateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("hcode_index", "1");

        request.timeout("1s");
        User user = new User("hzh", );

        request.doc(JSON.toJSONString(user), XContentType.JSON);

        UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);
        System.out.println(response.status()); //成功返回 OK
        System.out.println(response.toString());
    }

删除文档信息

COPY void deleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("hcode_index", "1");

        request.timeout("1s");

        DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        System.out.println(response.status()); //成功返回 OK
        System.out.println(response.toString());
    }

批量操作

COPYvoid BulkRequest() throws IOException {
        BulkRequest request = new BulkRequest();
        request.timeout("10s");
        ArrayList<Object> list = new ArrayList<>();
        list.add(new User("hcode", ));
        list.add(new User("himit", ));
        list.add(new User("youth", ));

        //批量请求,批量更新,删除都差不多!!!不设置id就会自动生成随机id,演示为批量插入
        for (int i = ; i < list.size(); i++) {
            request.add(new IndexRequest("hcode_index")
                    .id("" + (i + ))
                    .source(JSON.toJSONString(list.get(i)), XContentType.JSON));
        }

        BulkResponse response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        System.out.println(response.hasFailures());//是否失败,false表示成功,true表示失败
    }

搜索查询+高亮

COPY void Query() throws IOException {
        SearchRequest request = new SearchRequest();
        //创建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 使用QueryBuilders工具,精确查询term
        //QueryBuilders.matchAllQuery() 匹配所有
        TermQueryBuilder termQuery = QueryBuilders.termQuery("name", "hcode");

        //配置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name"); //绑定属性
        highlightBuilder.requireFieldMatch(false); //关闭多个高亮,只显示一个高亮
        highlightBuilder.preTags("<p style='color:red'>"); //设置前缀
        highlightBuilder.postTags("</p>"); //设置后缀
        sourceBuilder.highlighter(highlightBuilder);

        sourceBuilder.query(termQuery);
        sourceBuilder.timeout(new TimeValue(, TimeUnit.SECONDS));

        request.source(sourceBuilder);

        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //获取结果对象
        SearchHits hits = response.getHits();

        System.out.println(JSON.toJSONString(hits));

        for (SearchHit searchHit : hits) {
            //获取高亮的html
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            HighlightField name = highlightFields.get("name");

            //替换原有的字段
            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();

            if (name != null) {
                Text[] fragments = name.fragments();
                String light_name = "";
                for (Text fragment : fragments) {
                    light_name += fragment;
                }
                sourceAsMap.put("name", light_name); //进行替换
            }


            System.out.println(searchHit.getSourceAsMap());
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Boot(一)简要概述以及简单项目的创建

    时代在变化,科技在进步,程序员不努力,终将会被时代淘汰,就好比SSH(struts+spring+hibernate),SSM(Spring+SpringMVC...

    HcodeBlogger
  • Java中的IO流(一)字节流的常用操作

    今天带来的是JAVA的IO流中的字节流,InputStream和OutputStram子类流的用法。

    HcodeBlogger
  • Spring Cloud(三)负载均衡,服务熔断,服务降级,服务限流

    整合依赖spring-cloud-starter-netflix-eureka-client里面也包含了ribbon的依赖

    HcodeBlogger
  • [每日一题]C语言程序设计教程(第三版)课后习题5.7

    题目描述 给出一个不多于5位的整数,要求 1、求出它是几位数 2、分别输出每一位数字 3、按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5...

    编程范 源代码公司
  • 北京发布自动驾驶路测新规,可进行载人测试

    12月13日,北京市交通委发布了新修订的《北京市自动驾驶车辆道路测试管理实施细则(试行)》,其中提到自动驾驶车辆可以申请进行“载人测试及载物测试”。

    镁客网
  • 基于 SpringCloud 微服务架构的广告系统(第二部分:广告投放、微服务调用与断路器)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    营琪
  • 2020年物联网趋势:你需要知道的5件事

    随着技术的不断发展,对于个人和组织而言,利用物联网设备来提高生产力和盈利能力至关重要。您可以在2020年看到以下5种物联网趋势。

    用户4122690
  • 部分学者认为图灵测试缺乏价值

    据科技资讯网TechInsider 2015年8月18日报道,部分人工智能科学家认为图灵测试几乎毫无价值,而且还使得人们背离了真正的人工智能科学。 图灵测试是以...

    人工智能快报
  • 为了自动驾驶的商业化,韩国建造了一个新的“城市” | 热点

    镁客网
  • 自动驾车可在北京临时上路了!但,有一个条件。

    IT派 - {技术青年圈} 持续关注互联网、大数据、人工智能领域 ? 导语:12月18日,北京市交通委发布了指导文件规范推动自动驾驶技术的发展。根据新规,在...

    IT派

扫码关注云+社区

领取腾讯云代金券