Elasticsearch7.6.0

作者:神秘网友 发布时间:2022-06-23 07:03:57

Elasticsearch7.6.0

ElasticSerach 7.6.0

6.x和7.x的区别十分大

1.1 概念

概念:开源的高扩展的分布式全文搜索引擎,可以近乎实时的存储,检索数据。可扩展到上百台服务器,处理PB级别(大数据)的数据。Es是使用java开发的并使用Lucene(也是java开发的工具包)作为核心来实现所有索引和搜索的功能,通过简单的RestfulApi来隐藏Lucene的复杂性,从而简化全文搜索。ElasticSearch已超过Solr称为排名第一的搜索引擎应用。Solr也是基于Java开发的,基于Lucene的搜索引擎。

1.2 使用

维基百科、国外新闻网站、StackOverFlow、Github、电商网商、日志数据分析ELK(ElasticSearch+Logstash+Kibana)

ELK:

Logstash:用于数据收集

ElasticSearch:数据存储分析和搜索

Kibana:用于结果展示

1.3 Es和Solr对比Es开箱使用,相比Solr更简单。Solr使用Zookeeper进行分布式管理,而Es自身带有分布式协调管理功能。Solr支持更多格式数据,如Json、Xml、Csv。而Es只支持Json格式。Solr官方提供功能更多,而Es本身更注重核心功能,高级功能多有第三方插件提供,例如图形化界面由Kibana支持Solr查询速度更快,但更新索引慢,用于电商查询多的应用,Es建立索引快,查询相比Solr慢。Solr是传统搜索应用的有力解决方案,Es适用于新兴的实时搜索应用。Solr比较成熟,社区活跃。Es相对开发维护者较少,更新快,学习成本高。1.4 安装准备工作

JDK1.8:ES要求的JDK版本最低是1.8

ElasticSearch:7.6.0版本(https://www.elastic.co/cn/downloads/elasticsearch)

Kibana:需要与ES版本保持一致,也是7.6.0版本(https://www.elastic.co/cn/downloads/kibana)

IK分词器:中文分词器,需要与ES版本保持一致,也是7.6.0版本(https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.6.0)

ElasticSearch-Head:连接ES的图形化客户端,需要Node.js环境,先安装Node.js(http://nodejs.cn/download/、https://github.com/mobz/elasticsearch-head)

1.5 安装

将上述的安装包,下载后进行解压。

Elasticsearch7.6.0

Elasticsearch7.6.0

Elasticsearch7.6.0

Elasticsearch7.6.0

ES运行(单机):elasticsearch-7.6.0\bin\elasticsearch.bat 双击直接执行 http://127.0.0.1:9200

Kibana运行:kibana-7.6.0-windows-x86_64\bin\kibana.bat http://127.0.0.1:5601

ElasticSearch-Head:先进行编译,npm install,安装完成后直接 npm run start运行即可 http://127.0.0.1:9100

IK分词器:直接将IK分词器目录直接copy到ES的plugins下,并改名为目录名为analysis-ik(否则加载不到),ES启动时就会自动加载插件

1.6 启动访问1.6.1 启动ES、ES-Head

访问ES http://127.0.0.1:9200 出现下面结果,ES启动成功,ES对外API端口是9200,ES集群内部通讯端口为9300

Elasticsearch7.6.0

访问ES-Head http://127.0.0.1:9100,发现连接 ES http://127.0.0.1:9200 出现跨域问题

Elasticsearch7.6.0

1.6.2 Head工具跨域问题

解决ES-Head连接ES的跨域问题:

配置 elasticsearch-7.6.0\config\elasticsearch.yml 配置文件,添加跨域支持,然后重启ES,即可

# 开启跨域http.cors.enabled: true# 所有人访问http.cors.allow-origin: "*"

连接成功

Elasticsearch7.6.0

1.6.3 启动 Kibana

访问 http://127.0.0.1:5601

Elasticsearch7.6.0

测试IK分词器,能运行成功并且成功分词,就代表IK分词器配置成功    GET _analyze{  "analyzer": "ik_smart",  "text": "我是中国人"}GET _analyze{  "analyzer": "ik_max_word",  "text": "我是中国人"}

Elasticsearch7.6.0

Elasticsearch7.6.0

1.7 分词器

分词器,作用是将一段字符串拆分成一个个的关键字,我们在搜索的时候,会将我们输入的关键字进行分词,会将索引库中的数据进行分词,然后进行一个匹配操作(搜索出匹配度相关的数据),ES相似度匹配的结果与所选择的分词器类别息息相关。ES默认的分词器为standard,是将每个字看做一个词,但显然不符合我们中文的场景,所以需要使用IK分词器,进行词组的划分。

分词器:

Standard:单字切分法,一个字(对于英文为一个单词)切分成一个词,ES默认内置分词器。CJKAnalyzer: 二元切分法, 把相邻的两个字, 作为一个词。SmartChineseAnalyzer: 对中文支持较好, 但是扩展性差, 针对扩展词库、停用词均不好处理。Whitespace分词器:去除空格,不支持中文,对生成的词汇单元不进行其他标准化处理。language分词器:特定语言的分词器,不支持中文。IK-analyzer: 在做中文搜索时,最受欢迎的分词器,支持自定义词库。1.8 IK分词器1.8.1 IK分词模式

IK分词器有两种分词模式:ik_max_wordik_smart模式。

1、ik_max_word(最细粒度的拆分)

会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。

2、ik_smart(粗粒度的拆分)

会做最粗粒度的拆分,但不会重复,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。

1.8.2 自定义分词字典

Elasticsearch7.6.0

有时候,ik分词的结果,不符合我们的预期,比如:我是程序猿,预期结果:我、是、程序猿,但是ik分词器将【程序猿】三个字也拆分了,这个时候我们需要自定义扩展字典,并注入到配置文件中。

编写自定义词典(在elasticsearch-7.6.0\plugins\analysis-ik\config,下面新建 my.dic文件(名字自定义),并写入【程序猿】字典值到my.dic中)

注入到字典配置文件中(elasticsearch-7.6.0\plugins\analysis-ik\config\IKAnalyzer.cfg.xml),并重启ES。

?
?my.dic

Elasticsearch7.6.0

1.9 ES的核心概念

ES是面向文档

关系型数据库(例:Mysql)ES数据库DataBase索引Indices表Table类型types(慢慢弃用,7.0已经过时,8.0就会彻底弃用)行rows文档documents列字段Columns字段fields

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

物理设计

Elasticsearch7.6.0

ES在后台把每个索引划分成多个分片,每个分片可以在集群中的的不同服务器间迁移,ES将数据分别存储在每个分片上,分片又存储在不同的节点上,保证了高可用。

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

集群(cluster): 由一个或多个节点组成, 并通过集群名称与其他集群进行区分

节点(node): 单个 ElasticSearch 实例. 通常一个节点运行在一个隔离的容器或虚拟机中

索引(index): 在 ES 中, 索引是一组文档的集合

分片(shard): 因为 ES 是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片. ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节.主分片数在索引创建时指定,后续不允许修改,除非 Reindex,重建索引

副本(replica): ES 默认为一个索引创建 5 个主分片(7.0版本以后,默认为1个主分片), 并分别为其创建1个副本分片. 也就是说每个索引都由 5 个主分片组成, 而每个主分片都相应的有一个 copy。对于分布式搜索引擎来说, 分片及副本的分配将是高可用及快速搜索响应的设计核心.主分片与副本都能处理查询请求,它们的唯一区别在于只有主分片才能处理索引请求.副本对搜索性能非常重要,同时用户也可在任何时候添加或删除副本。额外的副本能给带来更大的容量, 更高的呑吐能力及更强的故障恢复能力。主分片可读可写,副本只能读。

逻辑设计:

文档:

ES是面向文档的,索引和搜索数据的最小单位是文档。

自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value,例如:name:张三。可以是层次性的,一个文档中包含子文档,复杂的逻辑实体就是这么来的。就是一个json对象灵活的数据结构,文档不依赖于预先定义的模式,关系型数据库中需要提前定义字段才能使用,在ES中,对于字段是非常灵活的,有时候可以忽略该字段或者动态的添加一个新的字段。

类型:

类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。类型中对于字段的定义称为映射,比如name映射为字符串类型。虽说文档是无模式的,不需要拥有映射中所定义的所有字段,比如新增一个字段,那么ES会自动的将新增的字段加入映射,但是这个字段不确定是什么类型的,ES就会自动判断字段类型,但是可能判断的是错误的,所以最安全的方式是提前定义好所需要的映射,这点跟关系型数据库很像,先定义好字段在使用,避免出现问题。

索引:

索引是映射类型的容器,ES中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后被存储到各个分片上。

2.0 倒排索引(反向索引)

ES使用的是一种称为倒排索引的结构,采用Lucene倒排索引为底层,这种结构适用于全文搜索。实现比关系型数据库更快的过滤方法。有利于ES在不扫描全部文档的情况下,找到哪些关键字存在于哪些文档中。

正排索引:

当用户发起查询时(假设查询为一个关键词),搜索引擎会先扫描索引库中的所有文档,找出所有包含关键词的文档,这种从文档中去查找是否含有关键词的方法叫做正向索引

正排索引:基于文档建立索引,建立方便,维护简单,检索效率低。扫描文档 ---关键字

倒排索引:

倒排索引:基于字、词建立索引,建立维护复杂,检索效率高。关键字 -- 文档

Elasticsearch7.6.0

倒排索引的核心分为两部分:

第一部分为单词词典(Term Dictionary),记录所有文档的单词以及单词到倒排列表的关联关系。在实际生产中,单词量会非常大,所以实际会采用 B+ 树和哈希拉链法去存储单词的词典,以满足高性能的插入与查询。

第二部分是倒排列表(Posting List),它记录了单词对应的文档id,倒排列表是由倒排索引(Posting) 组成。,找到文档的id,在去找对应的文档。

倒排索引的使用场景:

搜索引擎,根据关键字,找到所有关联的文章。

2.1 RestfulApi

字段类型:

Text, 字符串类型(可被分词)Keyword, 字符串类型(不可被分词,是一个整体)Integer,Long,Date,(日期类型,可自定义格式)Float,Double,Boolean,Object,Auto, 自动检测类型Nested, 嵌套类型(Object数据类型的特殊版本)Ip, IP地址类型(适用于ip段的查询106.94.0.0/16,查询更快)
请求方式url功能PUTip:port / 索引名称 / 类型名称 / 文档id创建文档(指定id)POSTip:port / 索引名称 / 类型名称创建文档(随机id)POSTip:port / 索引名称 / 类型名称 / 文档id / _update修改指定文档DELTEip:port/索引名称/类型名称/文档id删除指定文档GETip:port/索引名称/类型名称/文档id获取指定文档POSTip:port/索引名称/类型名称/_search查询所有文档

可以直接使用kibana测试,类型Type在7.0版本后就开始过时了,8.0彻底废弃,不建议在使用,直接使用默认的 _doc

2.1.1 创建索引:

Elasticsearch7.6.0

查看ES索引数据存储结果:

Elasticsearch7.6.0

2.1.2 创建索引规则:

Elasticsearch7.6.0

Elasticsearch7.6.0

Elasticsearch7.6.0

2.1.3 获取索引信息:

Elasticsearch7.6.0

2.1.4 默认索引字段类型:

Elasticsearch7.6.0

Elasticsearch7.6.0

2.1.5 扩展命令:

GET /_cat/indices?v 查看ES中所有索引的统计信息。

Elasticsearch7.6.0

2.1.6 修改索引:使用PUT命令(不推荐使用,全量覆盖,参数中缺少的字段,es会将其更新为空) PUT /索引/类型/id使用POST命令(增量更新,参数中缺少的字段,es不会更新为空) POST/索引/类型/id/_update

PUT更新前:

Elasticsearch7.6.0

PUT更新后:

Elasticsearch7.6.0

Elasticsearch7.6.0

POST更新后:

Elasticsearch7.6.0

Elasticsearch7.6.0

2.1.7 删除索引:

通过DELETE 命令,可以删除 索引或文档

2.1.8 查询(重点)

原生restful的api针对于入门学习,实际开发中我们并不会这样调用,开发中使用es封装的api

Elasticsearch7.6.0

简单查询:根据id获取:GET /索引/类型/文档id根据条件获取:GET /索引/类型/_search?q=属性:值复杂查询(_search)

match和term的区别

match会进行分词,对分词进行匹配,对字段进行模糊匹配;

term不会进行分词,它只对字段的分词进行精确匹配;

比如,对于文档中text类型的字段name=张三,match查询条件name:张三能查到,但term不能;

因为张三分词后是张,三;term会到倒排索引中找张三但是无法匹配
再比如name=张三,如果查询条件为name:张,无论是term还是match都会匹配到
match和term都会从倒排索引里面找,重点在于match会将条件进行分词,而term不会对条件分词

_search 查询

GET /索引/类型/_search

match查询:match查询会将我们的查询的关键字进行分词(分为 程序猿+甲),然后去匹配,但由于我们未设置索引的name字段类型,es默认name为text类型,es对索引的字段name也会进行分词分为 程序猿+甲+乙+丙几种,所以能匹配到包含程序猿的

GET /li/_doc/_search{  "query": {    "match": {      "name":"程序猿甲"    }  }}
Elasticsearch7.6.0

Elasticsearch7.6.0

_source 限制返回属性

ES默认是返回文档中的所有字段,我们可以使用_source进行限制字段返回

GET /li/_doc/_search{  "query": {    "match": {      "name":"程序猿"    }  },  "_source":["name","age"]}
Elasticsearch7.6.0Elasticsearch7.6.0from、size分页

from:开始下标 size:每页查询条数

GET /li/_doc/_search{  "query": {    "match": {      "name": "程序猿"    }  },  "sort": {    "age": {      "order": "desc"    }  },  "from": 0,  "size": 1}

Elasticsearch7.6.0

bool 多条件组合查询关键字对应mysql中的关键字must等同于mysql中的 andshould等同于mysql中的 ormust_not等同于mysql中的 notgtltgte=lte=
GET /li/_doc/_search{  "query": {    "bool": {      "must": [        {          "match": {            "name": "程序猿乙"          }        },        {          "match": {            "age": "26"          }        }      ]    }  }}

Elasticsearch7.6.0

GET /li/_doc/_search{  "query": {    "bool": {      "should": [        {          "match": {            "desc": "最美不过程序猿"          }        },        {          "match": {            "age": "26"          }        }      ]    }  }}

Elasticsearch7.6.0

GET /li/_doc/_search{  "query": {    "bool": {      "must_not": [        {          "match": {            "desc": "最美不过程序猿"          }        },        {          "match": {            "age": "26"          }        }      ]    }  }}

Elasticsearch7.6.0

GET /li/_doc/_search{  "query": {    "bool": {      "should": [        {          "match": {            "name": "程序猿"          }        }      ],      "filter": {        "range": {          "age": {            "gt": 25          }        }      }    }  }}

Elasticsearch7.6.0

term 精确查询

term是直接去倒排索引进行词条的精确匹配。

构建测试数据:

name为text

desc为keyword

Elasticsearch7.6.0

PUT /li2{  "mappings": {    "properties": {      "name": {        "type": "text"      },      "desc": {        "type": "keyword"      }    }  }}PUT /li2/_doc/1{  "name":"程序猿甲",  "desc":"谈一个对象 desc"}PUT /li2/_doc/2{  "name":"程序猿乙",  "desc":"new一个对象 desc"}

开始查询

GET /li2/_doc/_search{  "query":{    "term":{      "name":"程"    }  }}

Elasticsearch7.6.0

GET /li2/_doc/_search{  "query":{    "term":{      "desc":"new一个对象 desc"    }  }}

Elasticsearch7.6.0

tem的多条件精确匹配
GET /li2/_doc/_search{  "query": {    "bool": {      "must": [        {          "term": {            "name": "甲"          }        },        {          "term": {            "desc": "谈一个对象 desc"          }        }      ]    }  }}

Elasticsearch7.6.0

highlight 高亮查询
GET /li2/_doc/_search{  "query": {    "match":{      "name":"程序"    }  },  "highlight": {    "fields":{      "name":{}    }  }}

Elasticsearch7.6.0

自定义高亮标签

pre_tags:前标签

post_tags:后标签

GET /li2/_doc/_search{  "query": {    "match":{      "name":"程序"    }  },  "highlight": {    "pre_tags":"p style='color:red'",    "post_tags":"/p",    "fields":{      "name":{}    }  }}

Elasticsearch7.6.0

3. 集成SpringBoot

找ElasticSearch官方文档

引入官方依赖,找到关键对象RestHighLevelClient

!--elasticsearch依赖--dependency    groupIdorg.springframework.boot/groupId    artifactIdspring-boot-starter-data-elasticsearch/artifactId/dependency

创建cilent对象 RestHighLevelClient

RestHighLevelClient restClient = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"),new HttpHost("127.0.0.1", 9201, "http")));
3.1 创建项目

创建maven项目,创建module(使用springboot的骨架创建)

Elasticsearch7.6.0

Elasticsearch7.6.0

3.2 修改ES核心包的版本

我们看到2.2.5的springboot中集成的是es的 6.8.6版本,所以需要修改版本号为我们的es版本,7.6.0,找到es版本的标签,直接在我们的pom文件中进行覆盖

Elasticsearch7.6.0

3.3 配置ES客户端对象操作ES的对象类型备注Transport Client客户端在ElasticSearch8中将被移除,在spring-data-elasticsearch:4.0版本中被标为过期,不推荐使用RestHighLevelClient客户端高级Restful客户端,灵活度更高,但操作对象需要格式转换。推荐使用ElasticsearchOperations接口直接注入使用,具体使用的客户端要看实现类所配置的客户端,也能使用,但是复杂查询可能比较麻烦ElasticsearchRepository接口Spring-data-elasticsearch 提供好的接口,只需要继承 ElasticsearchRepository 接口即可,底层使用的是ElasticsearchOperations 接口的方法(对ElasticsearchOperations接口的再次扩展)ElasticsearchTemplate实现类是 ElasticsearchOperations的实现,使用的是 Transport Client,在spring-data-elasticsearch:4.0版本中被标为过期,被ElasticsearchRestTemplate代替,不推荐使用ElasticsearchRestTemplate实现类是 ElasticsearchOperations的实现,使用的是 RestHighLevelClient

创建RestHighLevelClient 客户端

推荐使用这种,这种配置完客户端后就可以同时使用这两个对象 RestHighLevelClient、ElasticsearchRestTemplate
package com.yuening.esapi.config;import org.apache.http.HttpHost;import org.elasticsearch.client.RestClient;import org.elasticsearch.client.RestHighLevelClient;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.util.StringUtils;@Configurationpublic class ElasticSearchClientConfig {    /**     * es的集群节点配置     * 127.0.0.1:9200,127.0.0.1:9201,127.0.0.1:9202     */    @Value("${spring.elasticsearch.rest.uris}")    private String uri;    /**     * 创建es的客户端对象     *     * @return     */    @Bean    public RestHighLevelClient restHighLevelClient() {        //单机版本  集群版本 官方文档:        //RestHighLevelClient restClient = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"),new HttpHost("127.0.0.1", 9201, "http")));        if (StringUtils.isEmpty(uri)) {            throw new RuntimeException("elasticsearch uri is unset to properties file");        }        String[] nodes = uri.split(",");        HttpHost[] httpHosts = new HttpHost[nodes.length];        for (int x = 0; x  nodes.length; x++) {            String[] uris = nodes[x].split(":");            HttpHost httpHost = new HttpHost(uris[0], Integer.parseInt(uris[1]), "http");            httpHosts[x] = httpHost;        }        return new RestHighLevelClient(RestClient.builder(httpHosts));    }}
这种配置完客户端后还必须要手动创建 ElasticsearchRestTemplate 才可注入使用 ElasticsearchRestTemplate(否则会报找不到类)
@Configurationpublic class ElasticSearchClientConfig2 extends AbstractElasticsearchConfiguration {    /**     * es的集群节点配置     * 127.0.0.1:9200,127.0.0.1:9201,127.0.0.1:9202     */    @Value("${spring.elasticsearch.rest.uris}")    private String uri;    /**     * 初始化 RestHighLevelClient     * @return     */    @Override    @Bean    public RestHighLevelClient elasticsearchClient() {        final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo(uri.split(",")).build();        return RestClients.create(clientConfiguration).rest();    }    /**     * 初始化 ElasticsearchRestTemplate 才能使用     * @return     */    @Bean    public ElasticsearchRestTemplate elasticsearchRestTemplate() {        return new ElasticsearchRestTemplate(elasticsearchClient());    }}
3.4 简单测试

这里会使用ElasticsearchRestTemplate、ElasticsearchOperations、RestHighLevelClient

import org.elasticsearch.client.RequestOptions;import org.elasticsearch.client.RestHighLevelClient;import org.elasticsearch.client.indices.CreateIndexRequest;import org.elasticsearch.client.indices.CreateIndexResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.elasticsearch.core.ElasticsearchOperations;import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.io.IOException;@RestControllerpublic class TestController {    @Autowired    private ElasticsearchRestTemplate elasticsearchRestTemplate;    @Autowired    private ElasticsearchOperations elasticsearchOperations;    @Autowired    private RestHighLevelClient restHighLevelClient;    @GetMapping("/test")    public String test(){        boolean test = elasticsearchRestTemplate.createIndex("test");        return String.valueOf(test);    }    @GetMapping("/test2")    public String test2(){        boolean test2 = elasticsearchOperations.createIndex("test2");        return String.valueOf(test2);    }    @GetMapping("/test3")    public String test3() throws IOException {        CreateIndexRequest createIndexRequest = new CreateIndexRequest("test3");        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);        return String.valueOf(createIndexResponse.isAcknowledged());    }}
3.5 索引API
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;import org.elasticsearch.action.support.master.AcknowledgedResponse;import org.elasticsearch.client.RequestOptions;import org.elasticsearch.client.RestHighLevelClient;import org.elasticsearch.client.indices.CreateIndexRequest;import org.elasticsearch.client.indices.CreateIndexResponse;import org.elasticsearch.client.indices.GetIndexRequest;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTestclass EsApiApplicationTests {    @Autowired    RestHighLevelClient restHighLevelClient;    @Test    public void createIndex() throws IOException {        CreateIndexRequest createIndexRequest = new CreateIndexRequest("yu");        //可以设置索引字段规则,也可以不设置,es会自动设置        XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()                .startObject()                .startObject("properties")                .startObject("name").field("type", "keyword").endObject()                .startObject("age").field("type", "integer").endObject()                .startObject("desc").field("type", "text").endObject()                .endObject()                .endObject();        //也可以直接使用DLS语句中的json字符串 例如: createIndexRequest.mapping("",XContentType.JSON);        createIndexRequest.mapping(xContentBuilder);        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);        boolean acknowledged = createIndexResponse.isAcknowledged();        System.out.println("索引创建成功," + acknowledged);    }    @Test    public void existsIndex() throws IOException {        GetIndexRequest getIndexRequest = new GetIndexRequest("yu");        boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);        System.out.println("索引是否存在,"+exists);    }    @Test    public void deleteIndex() throws IOException {        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("yu");        AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);        System.out.println("索引删除成功,"+delete.isAcknowledged());    }}
3.6 文档API CRUD
package com.yuening.esapi;import com.alibaba.fastjson.JSONObject;import com.yuening.esapi.domain.Student;import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;import org.elasticsearch.action.bulk.BulkItemResponse;import org.elasticsearch.action.bulk.BulkRequest;import org.elasticsearch.action.bulk.BulkResponse;import org.elasticsearch.action.delete.DeleteRequest;import org.elasticsearch.action.delete.DeleteResponse;import org.elasticsearch.action.get.GetRequest;import org.elasticsearch.action.get.GetResponse;import org.elasticsearch.action.index.IndexRequest;import org.elasticsearch.action.index.IndexResponse;import org.elasticsearch.action.search.SearchRequest;import org.elasticsearch.action.search.SearchResponse;import org.elasticsearch.action.support.master.AcknowledgedResponse;import org.elasticsearch.action.update.UpdateRequest;import org.elasticsearch.action.update.UpdateResponse;import org.elasticsearch.client.RequestOptions;import org.elasticsearch.client.RestHighLevelClient;import org.elasticsearch.client.indices.CreateIndexRequest;import org.elasticsearch.client.indices.CreateIndexResponse;import org.elasticsearch.client.indices.GetIndexRequest;import org.elasticsearch.common.text.Text;import org.elasticsearch.common.xcontent.XContentBuilder;import org.elasticsearch.common.xcontent.XContentFactory;import org.elasticsearch.common.xcontent.XContentType;import org.elasticsearch.index.query.BoolQueryBuilder;import org.elasticsearch.index.query.MatchQueryBuilder;import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.index.query.RangeQueryBuilder;import org.elasticsearch.index.query.TermQueryBuilder;import org.elasticsearch.index.query.WildcardQueryBuilder;import org.elasticsearch.rest.RestStatus;import org.elasticsearch.search.SearchHit;import org.elasticsearch.search.SearchHits;import org.elasticsearch.search.builder.SearchSourceBuilder;import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;import org.elasticsearch.search.sort.SortBuilders;import org.elasticsearch.search.sort.SortOrder;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Map;@SpringBootTestclass EsApiApplicationTests {    @Autowired    RestHighLevelClient restHighLevelClient;    @Test    public void createDocument() throws IOException {        // PUT /yu/_doc/1        Student stu = new Student("张三", 18, "张三说我不是李四");        //构建索引请求,参数为索引名称        IndexRequest indexRequest = new IndexRequest("yu");        //设置文档id        indexRequest.id("1");        //将我们的数据放入请求中 json格式        indexRequest.source(JSONObject.toJSONString(stu), XContentType.JSON);        //发起创建索引的请求        IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);        RestStatus status = index.status();        System.out.println("文档创建成功," + status);    }    /**     * 获取文档     *     * @throws IOException     */    @Test    public void getDocument() throws IOException {        // GET /yu/_doc/1        GetRequest getRequest = new GetRequest("yu", "1");        /**         * {         *     "_index":"yu",         *     "_type":"_doc",         *     "_id":"1",         *     "_version":1,         *     "_seq_no":0,         *     "_primary_term":1,         *     "found":true,         *     "_source":{         *         "age":18,         *         "desc":"张三说我不是李四",         *         "name":"张三"         *     }         * }         */        GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);        //获取文档中的_source内容,为string        String sourceAsString = getResponse.getSourceAsString();        Student student = JSONObject.parseObject(sourceAsString, Student.class);        System.out.println("文档获取成功," + JSONObject.toJSONString(student));        //获取文档中的_source内容为map        MapString, Object sourceAsMap = getResponse.getSourceAsMap();        System.out.println("文档获取成功," + JSONObject.toJSONString(sourceAsMap));    }    /**     * 更新文档     *     * @throws IOException     */    @Test    public void updateDocument() throws IOException {        UpdateRequest updateRequest = new UpdateRequest("yu", "1");        Student stu = new Student();        stu.setDesc("我说你就是李四啊啊啊啊");        // POST /yu/_doc/1/_update  {"doc":{"desc":"我说你就是李四啊啊啊啊"}}        updateRequest.doc(JSONObject.toJSONString(stu), XContentType.JSON);        /**         * {         *     "fragment":false,         *     "id":"1",         *     "index":"yu",         *     "primaryTerm":1,         *     "result":"UPDATED",         *     "seqNo":2,         *     "shardId":{         *         "fragment":true,         *         "id":-1,         *         "index":{         *             "fragment":false,         *             "name":"yu",         *             "uUID":"_na_"         *         },         *         "indexName":"yu"         *     },         *     "shardInfo":{         *         "failed":0,         *         "failures":[         *         *         ],         *         "fragment":false,         *         "successful":1,         *         "total":2         *     },         *     "type":"_doc",         *     "version":3         * }         */        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);        System.out.println("更新文档成功," + JSONObject.toJSONString(update));    }    /**     * 删除文档     *     * @throws IOException     */    @Test    public void deleteDocument() throws IOException {        DeleteRequest deleteRequest = new DeleteRequest("yu", "1");        DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);        RestStatus status = delete.status();        System.out.println("删除文档成功," + status);    }    /**     * 批量操作文档 新增、更新、删除     */    @Test    public void bulkOperateDocument() throws IOException {        //批处理请求        BulkRequest bulkRequest = new BulkRequest();        ListStudent studentList = new ArrayList();        Student stu1 = new Student("李四", 1, "我是李四");        Student stu2 = new Student("李四2", 2, "我是李四2");        Student stu3 = new Student("李四3", 3, "我是李四3");        Student stu4 = new Student("李天奎1", 4, "我是李天奎1我也是李天奎");        Student stu5 = new Student("李天奎2", 5, "我是李天奎2我也是李天奎");        Student stu6 = new Student("李天奎3", 6, "我是李天奎3");        studentList.add(stu1);        studentList.add(stu2);        studentList.add(stu3);        studentList.add(stu4);        studentList.add(stu5);        studentList.add(stu6);        studentList.forEach(p - {            //也可以创建批量更新、批量删除            //UpdateRequest updateRequest = new UpdateRequest("yu","1");            //DeleteRequest deleteRequest = new DeleteRequest("yu","1");            IndexRequest indexRequest = new IndexRequest("yu");            //indexRequest.id(); 可不设置id,es会默认生成一个字符串id            //将我们需要批量处理的数据 放入source中            indexRequest.source(JSONObject.toJSONString(p), XContentType.JSON);            //将请求添加到 批处理请求中            bulkRequest.add(indexRequest);        });        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);        boolean b = bulk.hasFailures();//是否有失败        BulkItemResponse[] items = bulk.getItems();//获取此次批处理执行的结果集合        System.out.println("批量插入文档成功,是否全部成功:" + !b + "," + JSONObject.toJSONString(items[0]));    }    /**     * 搜索文档     *     * @throws IOException     */    @Test    public void searchDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建搜索条件        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "李");        searchSourceBuilder.query(termQueryBuilder);        searchRequest.source(searchSourceBuilder);        //发起请求        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        SearchHits hits = searchResponse.getHits();        System.out.println("查询文档成功:" + JSONObject.toJSONString(hits));    }    /**     * 搜索文档 Query  Filter Query     *     * Query:查询结果会计算文档得分,并根据文档得分进行返回     * Filter Query:过滤查询,用在大数据量中筛选出查询的相关结果,不会计算文档得分     * 而且ES对filter query进行优化,对于经常使用的filter query的查询结果进行缓存,方便下次查询     *     * 注意:es中一旦同时使用了 query和filter query,es会先执行filter query再去执行query(类似于mysql的where条件过滤),可以提高查询效率     *     * @throws IOException     */    @Test    public void searchQueryAndFilterQueryDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建搜索条件        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "李天奎3");        //同时使用 query和filter query        searchSourceBuilder.query(termQueryBuilder).postFilter(QueryBuilders.termQuery("age",6));        searchRequest.source(searchSourceBuilder);        //发起请求        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        SearchHits hits = searchResponse.getHits();        System.out.println("查询文档成功:" + JSONObject.toJSONString(hits));    }    /**     * 搜索文档bool查询     *     * @throws IOException     */    @Test    public void searchBoolDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建搜索条件        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        //构建排序条件        searchSourceBuilder.sort(SortBuilders.fieldSort("age").order(SortOrder.DESC));        //构建match查询条件        MatchQueryBuilder nameMatchQueryBuilder = QueryBuilders.matchQuery("name", "李");        //构建range范围查询条件        RangeQueryBuilder ageRangeQueryBuilder = QueryBuilders.rangeQuery("age").from(3).to(6);        //构建通配符条件        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("desc", "*奎*");        //构建bool查询条件        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(nameMatchQueryBuilder).must(ageRangeQueryBuilder).must(wildcardQueryBuilder);        searchSourceBuilder.query(queryBuilder);        searchRequest.source(searchSourceBuilder);        //发起请求        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        //获取返回值,以及总记录数        SearchHits hits = searchResponse.getHits();        long value = searchResponse.getHits().getTotalHits().value;        System.out.println("bool查询文档成功,总记录数:" + value + ",详细结果:" + JSONObject.toJSONString(hits));    }    /**     * 分页查询文档     *     * @throws IOException     */    @Test    public void searchPageDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建SearchSourceBuilder        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        //构建分页查询 下标0开始-查5条        searchSourceBuilder.from(0).size(5);        //fetchSource可以指定只返回的字段,也可以指定需要排除的字段,第一个参数为:包含的字段数组 第二个参数为:需要排除的字段数组        searchSourceBuilder.fetchSource(new String[]{"name","desc"},new String[]{});        //构建通配符条件        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("desc", "*奎*");        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(wildcardQueryBuilder);        searchSourceBuilder.query(boolQueryBuilder);        searchRequest.source(searchSourceBuilder);        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        //获取返回值,以及总记录数        SearchHits hits = searchResponse.getHits();        long value = searchResponse.getHits().getTotalHits().value;        System.out.println("分页查询文档成功,总记录数:" + value + ",详细结果:" + JSONObject.toJSONString(hits));    }    /**     * 高亮查询文档     *     * @throws IOException     */    @Test    public void searchHighlightDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建SearchSourceBuilder        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        //构建HighlightBuilder高亮        HighlightBuilder highlightBuilder = new HighlightBuilder();        highlightBuilder.field("desc");        highlightBuilder.preTags("span style='color:red'");        highlightBuilder.postTags("/span");        //多个字段高亮的时候设置为false,否则只会高亮一个字段        highlightBuilder.requireFieldMatch(false);        //构建查询条件 desc中含有奎的,name中含有李的        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("desc", "*奎*");        WildcardQueryBuilder wildcardQueryBuilder2 = QueryBuilders.wildcardQuery("name", "*李*");        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().should(wildcardQueryBuilder).should(wildcardQueryBuilder2);        searchSourceBuilder.highlighter(highlightBuilder).query(boolQueryBuilder);        searchRequest.source(searchSourceBuilder);        ListMapString, Object mapList = new ArrayList();        //执行搜索请求        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        //解析高亮,返回结果中并不是直接把_source中的字段desc加上了高亮标签,而是单独返回了高亮的字段,需要我们自行进行替换        SearchHits hits = searchResponse.getHits();        for (SearchHit hit : hits.getHits()) {            //获取高亮的字段            MapString, HighlightField highlightFields = hit.getHighlightFields();            //获取_source map            MapString, Object sourceAsMap = hit.getSourceAsMap();            //获取高亮字段desc            HighlightField descHighlightField = highlightFields.get("desc");            //判断是不是为空,不然你匹配的第一个结果没有高亮内容,那么就会报空指针异常            if (null != descHighlightField) {                //获取高亮字段的文本内容(是个数组)                Text[] texts = descHighlightField.getFragments();                StringBuilder textStr = new StringBuilder();                for (Text text : texts) {                    textStr.append(text);                }                //替换掉_source中的desc字段内容                sourceAsMap.put("desc", textStr);                mapList.add(sourceAsMap);            }        }        System.out.println(JSONObject.toJSONString(mapList));    }}
3.7 聚合查询

聚合:英文为Aggregation,简称Aggs ,聚合查询是es除了搜索功能外提供的针对es数据做数据统计分析的功能。聚合有助于根据搜索查询提供聚合数据。聚合查询是数据库中重要的功能特征。它是基于查询条件来对数据进行分桶、计算的方法。有点类似于sql中的group by再加一下函数方法的操作。

注意:text类型的字段是不支持聚合的(text是支持分词的,无法聚合统计)

es中的聚合,例如:terms分组、max、min、avg、sum

kibana的语法:3.7.1 字段分组统计

size:如何不设置为0,会默认返回hits集合,默认返回前10条数据,而我们只需要聚合结果即可,设置为0即可

age_group:自定义的聚合的名字,一般以 字段+聚合函数类型,此处是按照age分组,所以命名为age_group

GET /yu/_doc/_search{  "query":{    "match_all":{}  },  "size":0,  "aggs":{    "age_group":{      "terms":{        "field":"age"      }    }  }}

Elasticsearch7.6.0

3.7.2 最大值最小值
GET /yu/_doc/_search{  "query":{    "match_all":{}  },  "size":0,  "aggs":{    "age_max":{      "max":{        "field":"age"      }    }  }}

Elasticsearch7.6.0

GET /yu/_doc/_search{  "query":{    "match_all":{}  },  "size":0,  "aggs":{    "age_min":{      "min":{        "field":"age"      }    }  }}

Elasticsearch7.6.0

3.7.3 平均值
GET /yu/_doc/_search{  "query":{    "match_all":{}  },  "size":0,  "aggs":{    "age_avg":{      "avg":{        "field":"age"      }    }  }}

Elasticsearch7.6.0

3.7.4 求和
GET /yu/_doc/_search{  "query":{    "match_all":{}  },  "size":0,  "aggs":{    "age_sum":{      "sum":{        "field":"age"      }    }  }}

Elasticsearch7.6.0

RestHighLevel的写法:
/**     * 聚合分组统计查询     * 例如:查询各年龄段的人数     *     * @throws IOException     */    @Test    public void searchAggsDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建SearchSourceBuilder        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        //构建查询,size默认为0  构建聚合        searchSourceBuilder.query(QueryBuilders.matchAllQuery())                .size(0)                .aggregation(AggregationBuilders.terms("age_group").field("age"))                //.aggregation(AggregationBuilders.terms("name_group").field("name"))                ;        searchRequest.source(searchSourceBuilder);        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        Aggregations aggregations = searchResponse.getAggregations();        //获取聚合统计分组的结果,因为年龄是int类型,使用ParsedLongTerms接收        ParsedLongTerms parsedLongTerms = aggregations.get("age_group");        //如果是name字段,那就用ParsedStringTerms类接收        //ParsedStringTerms parsedStringTerms = aggregations.get("name_group");        List? extends Terms.Bucket buckets = parsedLongTerms.getBuckets();        buckets.forEach(p - {            System.out.println("age:" + p.getKey() + ",count:" + p.getDocCount());        });    }    /**     * 聚合Max、Min、Sum、Avg查询     *     * @throws IOException     */    @Test    public void searchAggsMaxMinSumAvgDocument() throws IOException {        //构建搜索请求        SearchRequest searchRequest = new SearchRequest("yu");        //构建SearchSourceBuilder        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        //构建查询,size默认为0  构建聚合        searchSourceBuilder.query(QueryBuilders.matchAllQuery())                .size(0)                .aggregation(AggregationBuilders.max("age_max").field("age")) //设置max聚合查询                .aggregation(AggregationBuilders.min("age_min").field("age")) //设置min聚合查询                .aggregation(AggregationBuilders.sum("age_sum").field("age")) //设置sum聚合查询                .aggregation(AggregationBuilders.avg("age_avg").field("age")) //设置avg聚合查询        ;        searchRequest.source(searchSourceBuilder);        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);        Aggregations aggregations = searchResponse.getAggregations();        ParsedMax parsedMax = aggregations.get("age_max");        ParsedMin parsedMin = aggregations.get("age_min");        ParsedSum parsedSum = aggregations.get("age_sum");        ParsedAvg parsedAvg = aggregations.get("age_avg");        System.out.println("age_max:"+parsedMax.getValue());        System.out.println("age_min:"+parsedMin.getValue());        System.out.println("age_sum:"+parsedSum.getValue());        System.out.println("age_avg:"+parsedAvg.getValue());    }
总结

以上就是ES的入门级简单总结,学无止境,继续努力!!!

Elasticsearch7.6.0 相关文章

每天更新java,php,javaScript,go,python,nodejs,vue,android,mysql等相关技术教程,教程由网友分享而来,欢迎大家分享IT技术教程到本站,帮助自己同时也帮助他人!

Copyright 2021, All Rights Reserved. Powered by 跳墙网(www.tqwba.com)|网站地图|关键词