**本人博客网站 **IT小神 www.itxiaoshen.com
Elasticsearch官网地址 https://www.elastic.co/cn/elasticsearch/
Elasticsearch简称为ES,是一个基于Lecene开源的分布式高度可扩展的搜索和数据分析引擎,使用Java语言开发,带有RESTful 风格的API,是目前最流行的企业级搜索引擎;能够快速、接近实时地存储、搜索和分析大量数据;通常被用作底层引擎/技术,为具有复杂搜索特性和需求的应用程序提供支持。目前最新Release版本为7.14 ,7.15版本虽然已出现在官方但暂时还没有提供基于docker的镜像
Elasticsearch参考文档官网 https://www.elastic.co/guide/en/elasticsearch/reference/index.html
Elasticsearch为所有类型的数据提供近乎实时的搜索和分析。无论您使用的是结构化或非结构化文本、数字数据还是地理空间数据,Elasticsearch都能以一种支持快速搜索的方式有效地存储和索引它们。您可以远远超出简单的数据检索和聚合信息来发现数据中的趋势和模式。随着数据和查询量的增长,Elasticsearch的分布式特性使您的部署能够与之无缝地增长。
Solr官网 https://solr.apache.org
Solr是一个基于 Apache Lucene 之上的搜索服务器,开源的、基于 Java 的信息检索库。它的主要功能包括强大的全文搜索、高亮显示、分面搜索、动态集群、数据库集成、丰富的文档处理和地理空间搜索;Solr具有高度的可扩展性,提供容错的分布式搜索和索引,并支持许多世界上最大的互联网站点的搜索和导航功能。具有类似rest的API,可以通过JSON、XML、CSV或HTTP上的二进制文件将文档放入其中(称为“索引”),通过HTTP GET查询它,并接收JSON、XML、CSV或二进制结果。目前最新版本为8.9.0
Lucene官网 https://lucene.apache.org/
Apache Lucene™是一个开源的、高性能、全功能的文本搜索引擎库,完全用Java编写。它适用于几乎所有需要全文搜索的应用程序,特别是跨平台的应用程序。Lucene Core是一个Java库,提供强大的索引和搜索功能,以及拼写检查、点击高亮和高级分析/标记功能。
Apache Lucene为搜索和索引性能设置了标准,是Apache Solr和Elasticsearch的搜索核心,目前最新版本为8.9.0
索引就类似于目录,平时我们使用的都是索引,都是通过主键定位到某条数据,那么倒排索引,刚好相反,数据对应到主键.这里以一个博客文章的内容为例:
文章ID | 文章标题 | 文章内容 |
---|---|---|
1 | 浅析JAVA设计模式 | JAVA设计模式是每一个JAVA程序员都应该掌握的进阶知识 |
2 | JAVA多线程设计模式 | JAVA多线程与设计模式结合 |
假如,我们有一个站内搜索的功能,通过某个关键词来搜索相关的文章,那么这个关键词可能出现在标题中,也可能出现在文章内容中,那我们将会在创建或修改文章的时候,建立一个关键词与文章的对应关系表,这种,我们可以称之为倒排索引,因此倒排索引,也可称之为反向索引.如:
关键词 | 文章ID |
---|---|
JAVA | 1 |
设计模式 | 1,2 |
多线程 | 2 |
倒排索引一般由单词词典(Term Distionary)和倒排列表(PostingList)组成
单词词典
倒排列表一般存储在磁盘中,包含一下信息
动态索引通过在内存中维护临时索引,实现对动态文档和实时搜索的支持。对于服务器的内存总是有限的,随着加入的文档数据越来越多,临时索引消耗的内存也会不断增加。当最初分配的内存被使用完时就需要考虑使用什么策略来将临时索引的部分内容更新到磁盘索引中,以释放内存空间来存储新的数据。
常用的索引更新策略主要有四种:完全重建策略、再合并策略、原地更新策略及混合策略。
分析器一般都由三个构建组成,包括字符过滤器、分词器、token过滤器组成
中文分词器目前比较推荐的是IK分词器,为何要进行分词,如果没有分词“我爱中国”就会被拆分为四个单独的子,显然不符合我们中文的语义
IK分词器源码地址 https://github.com/hutea/ikanalyzer
IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 IK Analyzer 2012特性:
- 采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和智能分词两种切分模式;
- 在系统环境:Core2 i7 3.4G双核,4G内存,window 7 64位, Sun JDK 1.6_29 64位 普通pc环境测试,IK2012具有160万字/秒(3000KB/S)的高速处理能力。
- 2012版本的智能分词模式支持简单的分词排歧义处理和数量词合并输出。
- 采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符
- 优化的词典存储,更小的内存占用。支持用户词典扩展定义。特别的,在2012版本,词典支持中文,英文,数字混合词语。
分ik_smart:最粗力度拆,也即是最少的拆分
ik_max_word:也即是最细的粒度拆分
我们拿关系数据库做层级的类比,在Elasticsearch集群中可以存在多个index(索引可类比为数据库或者表,index下type这个在6.x开始就不推荐且只有index只能有一个type,在7.x版本则是已去掉了,一个 index 中只有一个默认的 type,即 _doc),每个索引中可以包含多个document(记录可类比为行),每个document下又可以包含多个Field(字段类比列),mapping相当于我们表结构schema
Elasticsearch官网下载地址
部署方式可以有多种,现在是容器化时代,由于之前文章我们已学习过Docker,所以我们选择基于Docker容器化部署,基于docker可以选择单机部署,基于K8S部署后续有时间再补充;可以选择单节点集群或多节点集群部署,我们直接选择官网例子基于单台宿主机docker-compose三个节点的集群部署
默认情况下,Elasticsearch会根据节点的角色和节点容器可用的总内存自动调整JVM堆的大小。对于大多数生产环境,我们建议使用此默认分级。如果需要,您可以通过手动设置JVM堆大小来覆盖默认大小。
要在生产中手动设置堆大小,绑定挂载在/usr/share/elasticsearch/config/ JVM .options下的JVM选项文件。D,其中包含所需的堆大小设置。
为了进行测试,您还可以使用ES_JAVA_OPTS环境变量手动设置堆大小。例如,要使用16GB,请指定-e
ES_JAVA_OPTS="-Xms16g -Xmx16g"与docker运行。ES_JAVA_OPTS变量覆盖所有其他JVM选项。ES_JAVA_OPTS变量覆盖所有其他JVM选项。我们不建议在生产环境中使用ES_JAVA_OPTS。
创建docker-compose.yml文档,在这个例子中使用ES_JAVA_OPTS环境变量手动设置堆大小为512MB。
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es01
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es02,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- elastic
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es02
environment:
- node.name=es02
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data02:/usr/share/elasticsearch/data
networks:
- elastic
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es03
environment:
- node.name=es03
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data03:/usr/share/elasticsearch/data
networks:
- elastic
volumes:
data01:
driver: local
data02:
driver: local
data03:
driver: local
networks:
elastic:
driver: bridge
运行docker-compose以启动集群,先创建网络
docker-compose up
运行后出现如下报错后退出了
es01 exited with code 78
es02 exited with code 78
es03 exited with code 78
我们通过其中一个容器查看日志 docker logs -tf --tail 10 052a5cf054a5
#通过root用户执行命令:
sysctl -w vm.max_map_count=262144
#查看结果:
sysctl -a|grep vm.max_map_count
#显示:
vm.max_map_count = 262144
#上述方法修改之后,如果重启虚拟机将失效,我们需要在 /etc/sysctl.conf文件最后添加一行vm.max_map_count=262144即可永久修改
重新执行即可正常使用,访问 http://192.168.50.94:9200/ ,至此我们安装完毕,非常简单
ES自身也提供很多集群维护查询命令,有兴趣可以自己查阅学习
//docker下载elasticsearch-head:5插件
docker pull mobz/elasticsearch-head:5
//docker启动elasticsearch-head:5容器,elastic_search_elastic为我们上一节安装的docker网络
docker run -d --network elastic_search_elastic -p 9100:9100 mobz/elasticsearch-head:5
启动后在流量访问9100端口:http://192.168.50.94:9100/,设置连接访问任意一台ES服务(本文为http://192.168.50.94:9200/,也即是采用上一小节在192.168.50.94部署docker的ES集群且暴露的9200端口),查看浏览控制台输出跨域错误,因此我们解决跨域问题
通过docker ps 找到我们ES集群所有容器,逐个进入容器的内容修改config修改config/elasticsearch.yml
文件,然后重新启动ES集群
Copy# 开启跨域
http.cors.enabled: true
# 允许所有
http.cors.allow-origin: "*"
再次访问就可以了
我们新建一个索引库,分片数为5副本数为2
五个主分片负载均衡分布在三个节点上,head插件也提供数据浏览、基本查询和符合查询,但我们基本不怎么使用,常用是使用Kibana的Devtools,下节我们安全后学习
Kibana官网地址 https://www.elastic.co/cn/kibana/
基于docker安装Kibana https://www.elastic.co/guide/en/kibana/current/docker.html
新建kibana.yml
server.name: kibana
# kibana的主机地址 0.0.0.0可表示监听所有IP
server.host: "0.0.0.0"
# kibana访问es的URL
elasticsearch.hosts: ["http://es01:9200","http://es02:9200","http://es03:9200"]
# 显示登陆页面
xpack.monitoring.ui.container.elasticsearch.enabled: true
通过Kinana官网的安装说明指引,我们创建docker-compose.yml,es01、es02、es03为之前建立ES集群服务器名称,elastic_search_elastic为建立ES集群创建网络,这样可以通过主机名称访问
version: '2'
services:
kibana:
image: docker.elastic.co/kibana/kibana:7.14.1
volumes:
- /home/docker_resource/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- "5601:5601"
environment:
SERVER_NAME: kibana
ELASTICSEARCH_HOSTS: '["http://es01:9200","http://es02:9200","http://es03:9200"]'
networks:
default:
external:
name: elastic_search_elastic
然后在docker-compose.yml的目录下执行命令启动kibana容器服务
docker-compose up -d
访问Kibana暴露的端口地址:http://192.168.50.94:5601
点击Dev tools进入到开发工具界面
elasticsearch-analysis-ik源码地址 https://github.com/medcl/elasticsearch-analysis-ik
通过GitHub上的安装说明我们下载预构建的包
预构建的包下载地址 https://github.com/medcl/elasticsearch-analysis-ik/releases
Analyzer: ik_smart, ik_max_word,
Tokenizer: ik_smart, ik_max_word
下载elasticsearch-analysis-ik-7.14.0.zip完毕后,在所有elasticsearch服务的安装目录下的plugins目录下新建ik目录,将上面zip包的内容全部放到ik
可以通过从宿主机拷贝到容器的方式
docker cp ik/ 9bad7f196e38:/usr/share/elasticsearch/plugins
拷贝到容器下的目录结构为下面所示
然后重启所有elasticsearch服务服务,每台elasticsearch服务会有出现这个日志信息,代表加载了ik插件
“message”: “loaded plugin [analysis-ik]”
还可以通过执行bin目录下./elasticsearch-plugin list 查看加载插件信息
通过kibana测试下ik
先试用ik_smart最粗力度拆分测试下
再使用ik_max_word最细的粒度拆分测试下
这就需要我们进行自定义拆分的词典,将自定义分词加到ik分词器的字典里
新建itxs.dic文件,在IKAnalyzer.cfg.xml修改如下内容itxs.dic
重启所有ES服务,查看ES服务的日志会发现有如下信息代表加载我们指定以分词字典文件
“message”: “[Dict Loading] /usr/share/elasticsearch/plugins/ik/config/itxs.dic”
重新执行查询后发现"云原生"已经被拆分为一个单词了
Elasticsearch文档官网地址 https://www.elastic.co/guide/en/elasticsearch/reference/7.14/index.html
官方提供非常详细开发和维护使用的指南,官方上中文文档已经比较老了,建议用最新发布版本的英文文档,如需全面学习有兴趣可以自己研究,其中也有REST APIs接口
text类型:会分词,先把对象进行分词处理,然后再再存入到es中。当使用多个单词进行查询的时候,当然查不到已经分词过的内容!
keyword:不分词,没有把es中的对象进行分词处理,而是存入了整个对象!这时候当然可以进行完整地查询!默认是256个字符!
动态映射:就是自动创建出来的映射,es 根据存入的文档,自动分析出来文档中字段的类型以及存储方式,这种就是动态映射
静态映射:在创建索引就指定好映射,属于明确的映射
格式: PUT /索引名称
PUT /es_dbtest
格式: GET /索引名称
GET /es_dbtest
格式: DELETE /索引名称
DELETE /es_dbtest
格式: PUT /索引名称/类型/id
PUT /es_dbtest/_doc/1
{"name": "张三","sex": 1,"age": 25,"address": "深圳龙华观澜"}
PUT /es_dbtest/_doc/2
{"name": "李四","sex": 1,"age": 28,"address": "深圳福田枢纽大厦"}
PUT /es_dbtest/_doc/3
{"name": "王五","sex": 2,"age": 18,"address": "深圳宝安机场"}
格式: PUT /索引名称/类型/id
PUT /es_dbtest/_doc/1
{"name": "张三三","sex": 1,"age": 25,"address": "深圳龙华观澜高尔夫"}
格式: GET /索引名称/类型/id
GET /es_dbtest/_doc/1
格式: DELETE /索引名称/类型/id
DELETE /es_dbtest/_doc/1
Restful是一种面向资源的架构风格,可以简单理解为:使用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT)描述操作。 基于Restful API ES和所有客户端的交互都是使用JSON格式的数据.其他所有程序语言都可以使用RESTful API,通过9200端口的与ES进行通信
GET查询
PUT添加
POST修改
DELETE删除
透明性,暴露资源存在。
充分利用 HTTP 协议本身语义,不同请求方式进行不同的操作
格式: GET /索引名称/类型/_search
GET /es_dbtest/_doc/_search
SQL: select * from student
如要查询age等于28岁的
格式: GET /索引名称/类型/_search?q=age:28
GET /es_dbtest/_doc/_search?q=age:28
SQL: select * from student where age = 28
如要查询age在25至26岁之间的
格式: GET /索引名称/类型/_search?q=age[25 TO 26] 注意: TO 必须为大写,
GET /es_dbtest/_doc/_search?q=age[25 TO 26]
SQL: select * from student where age between 25 and 26
格式: GET /索引名称/类型/_mget ,相当于SQL
GET /es_dbtest/_doc/_mget{ "ids":["2","3"] }
SQL: select * from student where id in (2,3)
格式: GET /索引名称/类型/_search?q=age:<=28
GET /es_dbtest/_doc/_search?q=age:<=28
SQL: select * from student where age <= 28
格式: GET /索引名称/类型/_search?q=age:>26
GET /es_dbtest/_doc/_search?q=age:>26
SQL: select * from student where age > 28
格式: GET /索引名称/类型/_search?q=age[25 TO 26]&from=0&size=1
GET /es_dbtest/_doc/_search?q=age[25 TO 26]&from=0&size=1
SQL: select * from student where age between 25 and 26 limit 0, 1
格式: GET /索引名称/类型/_search?__source=字段,字段
GET /es_dbtest/_doc/_search?_source=name,age
SQL: select name,age from student
格式: GET /索引名称/类型/_search?sort=字段 desc
GET /es_dbtest/_doc/_search?sort=age:desc
SQL: select * from student order by age desc
我们实际场景很少使用到上面请求体查询,更多会使用基于body内容的搜索功能,我们这里就不一一举例,有兴趣学习伙伴可以参照官网学习
GET /es_dbtest/_doc/_search
{
"query":{
"match": {
"name" : "张三三"
}
}
}
GET /es_dbtest/_doc/_search
{
"sort":[
{
"age": {
"order":"asc"
}
}
],
"from": 0,
"size": 2
}
GET /es_dbtest/_doc/_search
{
"term" : {
"age" : 18
}
}
GET /es_dbtest/_doc/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"age" : 18
}
}
}
}
}
GET /es_dbtest/_doc/_search
{
"query" : {
"constant_score" : {
"filter" : {
"range" : {
"age" : {
"gte" : 5,
"lt" : 40
}
}
}
}
},
"sort":[
{
"age": {
"order":"asc"
}
}
],
"from": 0,
"size": 2
}
GET /es_dbtest/_doc/_search
{
"query": {
"bool": {
"must": {
"match": {
"age": 18
}
},
"filter": {
"term": {
"sex": 2
}
}
}
}
}
可以针对结果进行高亮显示
自定义搜索高亮
通过_mget的API来实现的
批量对文档进行操作是通过_bulk的API来实现的
可以批量对多个索引进行增加或者删除等操作,减少网络请求次数,可以显著的提高索引的速度。
CURD只能对单条数据进行操作,如果是数据导入的情况下QPS会特别高。
多个API操作之间的结果互不影响。
bulk操作不能进行代码换行
bulk会将要处理的数据载入内存中,所以数据量是有限的,最佳的数据两不是一个确定的数据,它取决于你的硬件,你的文档大小以及复杂性,你的索引以及搜索的负载,一般建议是1000-5000个文档,大小建议是5-15MB,默认不能超过100M
请求方式:POST
请求地址:_bulk
请求参数:通过_bulk操作文档,一般至少有两行参数(或偶数行参数)
actionName:表示操作类型,主要有create,index,delete和update
action(行为) | desc(描述) |
---|---|
create | 文档不存在时,创建 |
update | 更新文档 |
index | 创建新文档,或者替换已经有的文档 |
delete | 删除一个文档 |
{"actionName":{"_index":"indexName", "_type":"typeName","_id":"id"}}{"field1":"value1", "field2":"value2"}
(1)批量创建文档create
POST _bulk
{"create":{"_index":"product", "_id":1}}
{"id":1,"name":"白菜","content":"甜","tags":["大", "绿"],"create_time":1630675861}
{"create":{"_index":"product", "_id":2}}
{"id":2,"name":"猪五花肉","content":"肥而不腻","tags":["色泽鲜艳", "新鲜"],"create_time":1630675861}
(2)批量修改update
POST _bulk
{"update":{"_index":"product", "_id":1}}
{"doc":{"name":"大白菜"}}
{"update":{"_index":"product", "_id":2}}
{"doc":{"name":"猪后腿肉"}}
(3)批量删除delete
POST _bulk
{"delete":{"_index":"product", "_id":1}}
{"delete":{"_index":"product", "_id":2}}
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html
找到官方提供客户端使用文档
本示例主要基于Spring Data的启动器spring-boot-starter-data-elasticsearch为核心,构建一个简单Spring Boot程序
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itxs</groupId>
<artifactId>elasticsearch-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.2</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<elasticsearch.version>7.14.1</elasticsearch.version>
</properties>
<repositories>
<repository>
<id>es-snapshots</id>
<name>elasticsearch snapshot repo</name>
<url>https://snapshots.elastic.co/maven/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
</dependencies>
</project>
application.yml文件
spring: elasticsearch: rest: uris: http://192.168.50.94:9200
当然也可以使用配置类的方式,下面ElasticSearchClientConfig.java是例子
package com.itxs.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("192.168.50.94", 9200, "http")));
return client;
}
}
创建实体类User
package com.itxs.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
private String address;
}
测试类
package com.itxs;
import com.alibaba.fastjson.JSON;
import com.itxs.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
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.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.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
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;
@SpringBootTest
@Slf4j
public class ElasticSearchTest {
private static String USER_INDEX_CONST ="user_index";
@Autowired
RestHighLevelClient restHighLevelClient;
//创建索引库
@Test
public void CreateIndex() throws IOException {
CreateIndexRequest request = new CreateIndexRequest(USER_INDEX_CONST);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
log.info("创建索引:{}",createIndexResponse);
}
//检查索引库是否存在
@Test
public void GetIndexExists() throws IOException {
GetIndexRequest request = new GetIndexRequest(USER_INDEX_CONST);
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
log.info("获取索引是否成功:{}",exists);
}
//删除索引库
@Test
public void DeleteIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest(USER_INDEX_CONST);
AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
log.info("删除索引是否成功:{}",delete.isAcknowledged());
}
//索引库里添加文档
@Test
public void AddDocument() throws IOException {
User user = new User("段乐乐", 20, "北京朝阳");
IndexRequest request = new IndexRequest(USER_INDEX_CONST);
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.source(JSON.toJSONString(user), XContentType.JSON);
IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
log.info("返回值内容:{},状态:{}",indexResponse.toString(),indexResponse.status());
}
//索引库里检查文档是否存在
@Test
public void GetDocumentExists() throws IOException {
GetRequest getRequest = new GetRequest(USER_INDEX_CONST, "1");
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
log.info("文档内容是否存在:{}",exists);
}
//查询索引库里文档内容
@Test
public void GetDocument() throws IOException {
GetRequest getRequest = new GetRequest(USER_INDEX_CONST, "1");
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
log.info("文档内容:{},全部内容:{}",getResponse.getSourceAsString(),getResponse);
}
//更新索引库里文档内容
@Test
public void UpdateDocument() throws IOException {
UpdateRequest updateRequest = new UpdateRequest(USER_INDEX_CONST, "1");
updateRequest.timeout(TimeValue.timeValueSeconds(1));
User user = new User("张三丰", 18, "上海浦东");
updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
log.info("更新文档结果状态:{}",updateResponse.status());
}
//删除索引库里文档内容
@Test
public void DeleteDocument() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest(USER_INDEX_CONST, "1");
deleteRequest.timeout(TimeValue.timeValueSeconds(1));
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
log.info("删除文档结果状态:{}",deleteResponse.status());
}
@Test
public void BulkDocument() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout(TimeValue.timeValueSeconds(1));
List<User> userList = new ArrayList<>();
userList.add(new User("韩梅梅",22,"长沙"));
userList.add(new User("马涛涛",25,"成都"));
userList.add(new User("李南",28,"南昌"));
for (int i = 0; i < userList.size(); i++) {
bulkRequest.add(new IndexRequest(USER_INDEX_CONST).id(""+ (i+10)).source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("批量添加文档结果状态:{}",bulk.status());
}
}
The Elastic Stack官方地址 https://www.elastic.co/cn/elastic-stack/
Elastic Stack核心产品包括 Elasticsearch、Kibana、Beats 和 Logstash(也称为 ELK Stack)。能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。Elasticsearch是位于Elastic Stack核心的分布式搜索和分析引擎,Logstash和Beats有助于收集、聚合和丰富数据,并将其存储在Elasticsearch中。Kibana使您能够交互式地探索、可视化和共享对数据的见解,并管理和监控堆栈。Elasticsearch是索引、搜索和分析魔术发生的地方
本篇只是入门,下篇我们再来学习Elasticsearch进阶内容和ELK等Elastic Stack技术栈研究已经基于搜索引擎的项目实战,希望一起学习的伙伴觉得不错的可以关注下本人的博客网站