一、ElasticSearch简介

1、概述

ES是一个使用Java语言并且基于Lucene编写的搜索引擎框架,他提供了分布式的全文搜索功能,提供了一个统一的基于RestFul风格的WEB接口,官方客户端也对多种语言都提供了相应的API。

Lucene: Lucene本身就是一个搜索引擎的底层。

分布式: ES主要是为了突出他的高扩展能力。

全文检索: 将一段词语进行分词,并且将分出的单个词语统一的放到一个分词库中,在搜索时,根据关键字去分词库中检索,找到匹配的内容。(倒排索引)

RestFul风格的WEB接口: 操作ES很简单,只需要发送一个HTTP请求,并且根据请求方式的不同,携带参数的不同,执行相应的功能。

2、ES和Solr比较

  1. Solr在查询死数据时,速度相对ES更快一些。但是数据如果是实时改变的,Solr的查询速度就会降低很多,ES查询的效率基本没有变化。
  2. Solr搭建基于需要依赖Zookeeper来帮忙管理。ES本身就支持集群的搭建,不需要第三方的介入。
  3. ES对现在云计算和大数据的支持特别好。

3、倒排索引

1、将存放的数据,以一定的方式进行分词,并且将分词的内容存放到一个单独的分词库中。

2、当用户去查询数据时,会将用户的查询关键字进行分词。

3、然后去分词库中匹配内容,最终得到数据的id标识。

4、根据id标识去存放数据的位置拉取到指定的数据。

二、ElasticSearch基于Docker方式安装

1、Kibana和IK分词器介绍

Kibana

kibana是一个针对Elasticsearch的开源分析及可视化平台,用于搜索、查看交互存储在Elasticsearch索引中的数据。使用Kibana,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理解,它操作简单,基于浏览器的用户界面可以快速创建仪表板实时显示ElasticSearch查询动态。版本必须与ES版本一致。

IK分词器

一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流。该分词器还负责记录各个term(词条)的顺序或psition位置(用于phrase短语和word proximity词近邻查询),以及term(词条)所代表的原始word(单词)的start(起始)和end(结束)的character offsets(字符偏移量)(用于高亮显示搜索的内容)。ES提供了很多内置的分词器,可以用来构建custm analyzers(自定义分词器)。

2、docker方式直接安装ES和Kibana

# 1、下载elasticsearch镜像
docker pull elasticsearch:6.5.4
# 2、下载kibana镜像
docker pull kibana:6.5.4
# 3、创建配置文件存放目录
mkdir -p /usr/local/docker/elasticsearch/config
# 4、创建数据存放目录
mkdir -p /usr/local/docker/elasticsearch/data
# 5、创建插件存放目录
mkdir -p /usr/local/docker/elasticsearch/plugins
# 6、追加配置文件内容,所有机器可以访问
echo "http.host: 0.0.0.0">>/usr/local/docker/elasticsearch/config/elasticsearch.yml
# 7、启动
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx128m" -v /usr/local/docker/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /usr/local/docker/elasticsearch/data:/usr/share/elasticsearch/data -v /usr/local/docker/elasticsearch/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:6.5.4
# 8、发现报错,Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes
# 需要给每个文件夹加权限
chmod -R 777 /usr/local/docker/elasticsearch/
# 9、重启elasticsearch容器
docker start 容器ID
# 10、安装kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.241.135:9200 -p 5601:5601 -d kibana:6.5.4
# 11、网址访问即可

3、docker-compose.yml方式安装ES和Kibana

# 1、新建一个目录
mkdir -p /usr/local/docker/elasticsearch/config
# 2、创建数据存放目录
mkdir -p /usr/local/docker/elasticsearch/data
# 3、创建插件存放目录
mkdir -p /usr/local/docker/elasticsearch/plugins
# 4、在镜像市场http://hub.daocloud.io找到elasticsearch和kibana镜像地址复制相应版本的地址
daocloud.io/library/elasticsearch:6.5.4
daocloud.io/library/kibana:6.5.4
# 5、检查是否安装docker-compose
docker-compose -v
# 6、如果没有安装则安装
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# 7、修改目录权限
chmod +x /usr/local/bin/docker-compose
# 8、新建一个docker-compose.yml文件
vim docker-compose.yml

配置docker-compose.yml文件

version: "3.1"
services:elasticsearch:# 镜像地址image: daocloud.io/library/elasticsearch:6.5.4restart: alwayscontainer_name: 'elasticsearch'environment:# 设置运行内存- "ES_JAVA_OPTS=-Xms512m -Xmx512m"ports:- 9200:9200# 挂载外部文件volumes:- /usr/local/docker/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml- /usr/local/docker/elasticsearch/data:/usr/share/elasticsearch/data- /usr/local/docker/elasticsearch/plugins:/usr/share/elasticsearch/pluginskibana:image: daocloud.io/library/kibana:6.5.4restart: alwayscontainer_name: 'kibana'ports:- 5601:5601environment:- elasticsearch_url=http://192.168.241.135:9200# 汉化- I18N_LOCALE=zh-CNdepends_on:- elasticsearch

执行启动

# 1、启动
docker-compose up -d
# 2、查看日志
docker-compose logs -f
# 3、网址访问即可

4、安装IK分词器插件

安装ES对应版本的分词器

https://github.com/medcl/elasticsearch-analysis-ik/releases

安装IK分词器

# 1、进入挂载目录下载对应版本的IK分词器(下载太慢,直接下载好通过XFTP工具上传到挂载目录)
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip
# 2、进入容器内部查看对应的目录下是否存在下载的文件
docker exec -it 容器ID /bin/bash
# 3、解压文件夹
tar -zxvf elasticsearch-analysis-ik-6.5.4.zip
# 4、修改整个文件夹的权限
chmod -R 777 elasticsearch-analysis-ik-6.5.4/
# 5、进入容器内部操作
docker exec -it 容器ID /bin/bash
# 6、进入bin目录下执行命令查看是否装好
elasticsearch-plugin list
# 7、重启ES
docker restart 容器名

在Kibana中测试IK分词器是否有效

三、ElasticSearch基于安装包方式安装

1、安装ES

1、下载地址

https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.tar.gz

2、解压

tar -zxvf elasticsearch-6.5.4.tar.gz

3、移动到安装位置

mv elasticsearch-6.5.4 /usr/local/program/

4、创建Elasticsearch用户

从5.0开始,ElasticSearch 安全级别提高了,不允许采用root帐号启动,所以我们要添加一个用户来启动ES和修改配置文件
# 创建ElaticSearch用户组
groupadd elasticsearch
# 创建用户
adduser es
# 设定密码
passwd es
# 将用户es添加到elasticsearch用户组
usermod -G elasticsearch es
# 添加权限
chown -R es elasticsearch-6.5.4

5、修改配置文件

1、取消如下注释,并修改为当前主机地址
# 进入配置文件目录
cd /usr/local/program/elasticsearch-6.5.4/config
# 编辑elasticsearch.yml文件
cluster.name: my-application
node.name: node-1
bootstrap.memory_lock: false
network.host: 0.0.0.0 # 所有都能访问,也可以设置为自己的服务器IP地址
http.port: 9200
discovery.zen.ping.unicast.hosts: ["0.0.0.0"]
discovery.zen.minimum_master_nodes: 1 #注意,因为本人目前是单节点,这里必须为1# 新增如下配置
transport.tcp.port: 9300
transport.tcp.compress: true
bootstrap.system_call_filter: false
2、修改/etc/sysctl.conf文件,添加如下配置,否则会报错

# 新增配置
vm.max_map_count=262144
# 退出保存后执行如下命令
sysctl -p
3、修改/etc/security/limits.conf文件,添加如下配置,否则会报错
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
# 新增配置
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
# 退出保存后执行如下命令
sysctl -p
4、编辑jvm.options文件,修改es启动的jvm参数
-Xms256m # 默认值为1g,改为256m
-Xmx256m
5、启动ElasticSearch
# 切换用户
su es
# 查看当前用户
who am i
# 后台启动
./elasticsearch -d
# 查看是否启动成功
jps
6、浏览器访问

2、安装Kibana

1、下载地址

https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-linux-x86_64.tar.gz
注意:Kibana需要与es版本对应

2、解压到安装位置

# 1、解压
tar -zxvf kibana-6.5.4-linux-x86_64.tar.gz
# 2、移动到安装位置并改名
mv kibana-6.5.4-linux-x86_64 /usr/local/program/kibana-6.5.4

3、修改配置文件

# 1、编辑kinaba.yml文件
vim /usr/local/program/kibana-6.5.4/config/kibana.yml
# 2、配置如下内容
server.port:5601
server.host:"localhost" # 由于es和kibana在同一台机器,可以使用localhost
elasticsearch.url:"localhost:9200"
kibana.index: ".kibana"
i18n.locale: "zh-CN"

4、启动Kibana

# 1、进入bin目录
cd bin
# 2、守护进程启动
nohup ./kibana &

5、查看Kibana进程

fuser -n tcp 5601

6、测试访问

7、设置时区显示和时间格式

3、安装IK分词器

1、下载对应版本的IK分词器

wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip

2、解压

# 1、安装unzip命令
yum update
yum install -y unzip
# 2、强行解压某文件到指定目录,解压压缩包到ik目录,并强行覆盖原有目录里内容
unzip -o elasticsearch-analysis-ik-6.5.4.zip -d ik

3、改名并移动到安装位置

IK分词器是一个插件,因此只需要将IK分词器放到ES目录的plugins文件夹下,然后重启ES即可

4、测试分词器是否安装成功

POST _analyze
{"analyzer": "ik_max_word","text":"中国人"
}

四、ElasticSearch的基本操作

1、ES的结构

1.1 索引Index、分片和备份

ES服务中,可以创建多个索引,类似MySql数据库

  1. 每一个索引默认被分成5片存储
  2. 每一个分片都会存在至少一个备份分片
  3. 备份分片默认不会帮助检索数据,当ES检索压力特别大的时候,备份分片才会帮助检索数据。
  4. 备份的分片必须放在不同的服务器中。

1.2 类型Type

一个索引下,可以创建多个类型,类似MySql数据库中的多个表

  1. 根据版本的不同,类型的创建个数也不同。

1.3 文档 Doc

一个类型下,可以有多个文档。类似MySql表中的多行数据

1.4 属性 Field

一个文档下,可以包含多个属性,类似MySql表中的一行数据存在多个列

2、操作ES的RestFul语法

2.1 GET 请求

# 查询索引信息
http://ip:port/index
# 查询指定的文档信息
http://ip:port/index/type/doc_id

2.2 POST 请求

# 查询文档,可以在请求体中添加json字符串来代替查询条件
http://ip:port/index/type/_search
# 修改文档,在请求体中指定json字符串代表要修改的具体信息
http://ip:port/index/type/doc_id/_update

2.3 PUT 请求

# 创建一个索引,需要在请求体中指定索引的信息,类型,结构
http://ip:port/index
# 代表创建索引时,指定索引文档存储的属性的信息
http://ip:port/index/type/_mappings

2.4 DELETE 请求

# 删除索引,会删除所有数据,类似删除数据库
http://ip:port/index
# 删除指定的文档,类似MySql中删除一条数据
http://ip:port/index/doc_id

3、索引的操作

3.1 创建索引

# 创建一个索引
PUT /persion
{"settings": {//number_of_shards:分片(默认5个),只能在创建 index 指定,后期无法修改"number_of_shards": 5,//number_of_replicas:备份(默认一个),可以在线修改"number_of_replicas": 1}
}

3.2 查看索引信息

3.2.1 Kibana 中直接查看

3.2.2 请求方式查看

# 查看索引信息
GET /persion
# 返回数据
{"persion" : {"aliases" : { },"mappings" : { },"settings" : {"index" : {"creation_date" : "1597976845612","number_of_shards" : "5","number_of_replicas" : "1","uuid" : "r0pobFOMSUaDhh7Lw7A6wA","version" : {"created" : "6050499"},"provided_name" : "persion"}}}
}

3.3 删除索引

# 删除索引
DELETE /persion
# 返回数据
{"acknowledged" : true
}

4、ES中Field中可以指定的类型

字符串类型:

  1. text:用于全文搜索。会将当前Field就行分词。
  2. keyword:当前Field不会被分词。

数值类型:

  1. long
  2. integer
  3. short
  4. byte
  5. double
  6. float
  7. half_float:精度比float小一半
  8. scaled_float:根据一个long和scaled来表达一个浮点型,long-345,scaled-100,表示成3.45

时间类型:

  1. date类型,针对时间类型可以指定具体的格式

布尔类型:

  1. boolean类型,表达true和false

二进制类型:

  1. binary类型暂时支持Base64 encode string

范围类型:

  1. long_range:赋值时,无序指定具体的内容,只需要存储一个范围即可,指定gt,lt,gte,lte
  2. integer_range:同上
  3. double_range:同上
  4. float_range:同上
  5. date_range:同上
  6. ip_range:同上

经纬度类型:

  1. geo_point:用来存储经纬度的

ip类型:

  1. ip:可以存储IPV4和IPV6

其他数据类型可以参考官网: https://www.elastic.co/guide/en/elasticsearch/reference/6.5/mapping-types.html

5、创建索引并指定数据结构

# 创建索引,指定索引名称
PUT book
{"settings": {# 分片数"number_of_shards": 5,# 备分数"number_of_replicas": 1},# 指定数据结构"mappings": {# 类型 Type"novel":{# 文档存储的Field属性名称"properties":{# Field属性名"name":{# Field的类型"type":"text",# 分词器"analyzer":"ik_max_word",# 指定当前Field可以被作为查询的条件"index":true,# 是否需要额外存储(默认false)"store":false},"author":{"type":"keyword"},"count":{"type":"long"},"onLine":{"type":"date",# 时间类型的格式化方式"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"},"content":{"type":"text","analyzer":"ik_max_word"}}}}
}

6、添加新字段映射

## 追加属性
PUT book/novel/_mapping
{"properties": {"createTime":{"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}}
}

7、数据迁移

在ES中不允许对已经存在字段映射进行修改,若需要修改字段映射,需要创建新的索引进行数据迁移

# 1、在已经创建好新的索引,并设置好字段映射关系后,对数据进行迁移# 2、数据迁移
POST _reindex
{"source": {"index": "原索引名","type": "原类型"},"dest": {"index": "新索引名"}
}

8、文档操作之新建文档

文档在ES服务中的唯一标识,_index_type_id 三个内容为组合,锁定一个文档,操作是添加还是修改。

自动生成id

优点:自动生成的id太长,过于复杂,不利于操作

注意:使用POST请求,在不指定id的情况下会自动生成,但是使用PUT请求,不指定id情况下会报错

{
“error”: “Incorrect HTTP method for uri [/book/novel?pretty] and method [PUT], allowed: [POST]”,
“status”: 405
}

自定义id

优点:方便好记、便于操作

注意:自定义id,可以使用POST和PUT请求,若不写id,PUT请求会报错

{
“error”: “Incorrect HTTP method for uri [/book/novel?pretty] and method [PUT], allowed: [POST]”,
“status”: 405
}

9、文档操作之修改文档

覆盖式修改

操作已存在的id,result会变为update,会覆盖之前的数据,如果Field有缺漏,会将缺漏Field的数据置为空,造成数据丢失

doc方式修改

可以设置修改部分Field信息,不会对所有Field造成影响

查看数据

先要配置,才能查看(需要索引中存在数据才能配置

10、文档操作之删除文档

五、SpringBoot集成ElasticSearch

1、SprinBoot连接ES的依赖

<properties><!--修改es版本--><elasticsearch.version>6.5.4</elasticsearch.version>
</properties>
<!--导入es的rest-high-level-client-->
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>6.5.4</version>
</dependency>
<!--引入fastjson-->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.49</version>
</dependency>

2、配置类

@Configuration
public class ElasticSearchConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(//若有多个就配置多个new HttpHost("192.168.241.135",9200,"http")));return restHighLevelClient;}
}

3、测试是否配置成功

@SpringBootTest
class ElasticsearchApplicationTests {@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testvoid t1() {//测试连接System.out.println(restHighLevelClient);}
}

六、Java操作索引的API

1、创建索引

@SpringBootTest
class ElasticsearchApplicationTests {   @Testvoid t2() throws IOException {//索引的settings,设置分片、备份Settings.Builder settings = Settings.builder().put("number_of_shards", 3).put("number_of_replicas", 1);//索引的结构mappingsXContentBuilder mappings = JsonXContent.contentBuilder().startObject()//属性集合.startObject("properties")//属性名.startObject("name")//指定属性类型.field("type","text").endObject().startObject("age").field("type","integer").endObject().startObject("birthday").field("type","date").field("format","yyyy-MM-dd").endObject().endObject().endObject();//将settings和mappings封装到一个Request对象,通过有参设置索引名,类似数据库名CreateIndexRequest request = new CreateIndexRequest("persion").settings(settings)//设置文档名,类似数据库中的表名.mapping("man",mappings);//通过restHighLevelClient对象连接ES并执行创建索引CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);System.out.println(response);}
}

查看是否创建索引成功

2、判断索引是否存在

@Test
void t3() throws IOException {//创建request对象GetIndexRequest request = new GetIndexRequest();//索引名request.indices("persion");//通过restHighLevelClient对象操作boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);System.out.println("persion索引是否存在:" + exists);
}

3、删除索引

@Test
void t4() throws IOException {//创建request对象DeleteIndexRequest request = new DeleteIndexRequest();//索引名request.indices("book");//通过restHighLevelClient对象操作AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);//输出状态System.out.println(response.isAcknowledged());
}

七、Java操作文档的API

1、添加文档

实体类:

@Data
/**无参构造*/
@NoArgsConstructor
/**有参构造*/
@AllArgsConstructor
public class Persion {/**忽略参数返回*/@JsonIgnoreprivate Integer id;private String name;private Integer age;private Date birthDay;
}

添加文档:

@SpringBootTest
class ElasticsearchApplicationTests {@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testvoid t5() throws IOException {//准备json数据Persion persion = new Persion(1,"张三",1,new Date());String json = JSON.toJSONString(persion);/*** 创建request对象* 参数说明:*      1、索引名,类似MySql中数据库*      2、类型名,类似要操作数据库中那一张表*      3、手动指定文档id*///创建request对象// 索引名 类型名IndexRequest request = new IndexRequest("persion","man",persion.getId().toString());request.source(json, XContentType.JSON);//通过restHighLevelClient对象操作IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);// 输出结果并返回System.out.println(JSON.toJSONString(response.getResult()));}
}

在Kibana中查看

2、修改文档

@SpringBootTest
public class DocTest {@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testvoid t2() throws IOException{//创建一个Map,指定需要修改的内容Map<String,Object> map = new HashMap<>();map.put("name","李四");/*** 创建request对象,封装数据* 参数说明:*      1、索引名*      2、类型名*      3、文档id*/UpdateRequest request = new UpdateRequest("persion","man","1");request.doc(map);//通过restHighLevelClient对象操作UpdateResponse update = restHighLevelClient.update(request, RequestOptions.DEFAULT);//输出返回结果System.out.println(JSON.toJSONString(update.getResult()));}
}

查看结果:

3、删除文档

@SpringBootTest
public class DocTest {@Autowiredprivate RestHighLevelClient restHighLevelClient;/*** 文档删除* @throws IOException*/@Testvoid t3() throws IOException{/*** 创建request对象,封装数据* 参数说明:*      1、索引名*      2、类型名*      3、文档id*/DeleteRequest request = new DeleteRequest("persion","man","1");//通过restHighLevelClient对象操作DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);//返回结果System.out.println(JSON.toJSONString(delete.getResult()));}
}

查看结果:

4、批量新增

@SpringBootTest
public class DocTest {@Autowiredprivate RestHighLevelClient restHighLevelClient;/*** 批量新增* @throws IOException*/@Testvoid t4() throws IOException{//准备json数据Persion p1 = new Persion(1, "张三", 23, new Date());Persion p2 = new Persion(2, "李四", 22, new Date());Persion p3 = new Persion(3, "王五", 21, new Date());String json1 = JSON.toJSONString(p1);String json2 = JSON.toJSONString(p2);String json3 = JSON.toJSONString(p3);//创建BulkRequest对象,将数据封装进去BulkRequest request = new BulkRequest();request.add(new IndexRequest("persion","man",p1.getId().toString()).source(json1,XContentType.JSON));request.add(new IndexRequest("persion","man",p2.getId().toString()).source(json2,XContentType.JSON));request.add(new IndexRequest("persion","man",p3.getId().toString()).source(json3,XContentType.JSON));//通过restHighLevelClient对象操作BulkResponse bulk = restHighLevelClient.bulk(request,RequestOptions.DEFAULT);//输出System.out.println(JSON.toJSONString(bulk));}
}

查看结果:

5、批量删除

@SpringBootTest
public class DocTest {@Autowiredprivate RestHighLevelClient restHighLevelClient;/*** 批量删除* @throws IOException*/@Testvoid t5() throws IOException{//创建BulkRequest对象,将数据封装进去BulkRequest request = new BulkRequest();request.add(new DeleteRequest("persion","man","1"));request.add(new DeleteRequest("persion","man","2"));request.add(new DeleteRequest("persion","man","3"));//通过restHighLevelClient对象操作BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);//输出System.out.println(JSON.toJSONString(bulk));}
}

查看结果:

八、文档查询

1、准备数据

实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmsLogs {@JsonIgnoreprivate Integer id;//编号private Date createDate;//创建日期private Date sendDate;//发送日期private String longCode;//发送的长号码private String mobile;//手机号private String corpName;//发送公司名称private String smsContent;//短信内容private Integer state;//状态 0-成功 1-失败private Integer operatorId;//运营商编号 1-移动 2-联通 3-电信private String province;//省份private String ipAddr;//下发服务器IP地址private Integer replyTotal;//短信状态报告返回时长(秒)private Integer fee;//费用@JsonIgnorepublic static String doc = "乌山镇,玉兰大陆第一山脉‘魔兽山脉’西方的芬莱王国中的一个普通小镇。朝阳初升,乌山镇这个小镇上依旧有着清晨的一丝清冷之气,只是小镇中的居民几乎都已经出来开始工作了,即使是六七岁的稚童,也差不多也都起床开始了传统性的晨练。乌山镇东边的空地上,早晨温热的阳光透过空地旁边的大树,在空地上留下了斑驳的光点。只见一大群孩子,目视过去估摸着差不多有一两百个。这群孩子分成了三个团队,每个团队都是排成几排,孩子们一个个都静静地站在空地上,面色严肃。这群孩子最北边一个团队的孩子大概六岁到八岁。而中间的一个团队,差不多是九岁到十二岁,最南边的则是一群十三岁到十六岁的少年。在这一大群孩子前方,便是三名壮硕的中年人,三个中年人都是穿着短背心以及粗布长裤。“想要成为一名伟大的战士,就必须从小刻苦锻炼。”为首的中年人背负着双手,昂着头颅冷然说道,那冷厉的目光更是朝最北边一个团队扫了过去,那群六七岁的孩子们一个个抿着嘴,乌溜溜的眼睛更是盯着这位中年人,丝毫不敢出声。为首的中年人名叫希尔曼,是乌山镇的拥有者‘巴鲁克家族’的护卫队队长。“你们都是普通人,不可能像那些大贵族一样有厉害的斗气密典修炼,想要出人头地,想要将来不被人瞧不起,你们就必须按照最古老、最简单、最基础的方法锻炼,锻炼身体、打熬力气,明白没有!”希尔曼目光扫向这一群孩子。“明白。”一群少年响亮地吼道。“很好。”希尔曼满意地冷漠点了点头,那些六七岁的孩子们眼中大多有着懵懵懂懂,而那些十几岁的少年们眼神都坚毅的很,因为他们明白希尔曼所说的含义。整个玉兰大陆几乎每一个男子都要从小努力锻炼,如果谁不刻苦训练,那他将来就会被人瞧不起!代表男人地位的,就是实力与金钱!一个没有实力的男人,就是女人也会瞧不起的。想要父母们引以为豪,想要女孩们崇拜,想要将来过的风光!就必须成为伟大的战士!他们都是平民,不可能修炼那些珍贵的斗气密典,他们唯一的方法就是从小锻炼身体、打熬力气!刻苦,努力!比那些贵族们花费更多的精力,花费更多的心血去努力!“早晨,朝阳升起,万物生机勃勃。此刻正是吸收天地的精华,提高我们身体潜力的最好时候,老规矩,双腿分开与肩同宽,双膝微微弯曲,双手收于腰部位置,成‘蕴气式’,做蕴气式的时候,要紧记‘集中注意力,保持心中平静,呼吸要自然’。”希尔曼冷漠说道。蕴气式,是锻炼身体的最简单也非常有效的办法,这是无数年来先辈积累出来的经验。顿时一两百个孩子都按照‘蕴气式’的姿势要求做好。“记住,集中注意力、心中平静、呼吸自然!”希尔曼走在少年群中,冷漠地说道。一眼看下去,很明显,南边的十几岁那个团队的少年们一个个都凝神静气、呼吸自然。同时一个个都做到了‘深、平、稳’。很显然在‘蕴气式’上都有了一些成就。不过再看北边六七岁的孩子,双膝弯的程度不同,双腿松松垮垮,明显没有力量,一点都不稳。希尔曼对着另外两位中年人说道:“你们分别负责南边和中央的两个团队,我去管理那些小孩子。”“是,队长。”那两名中年人当即应命,随后这二人分别仔细观看着中央、南边两个团队,时而还踢踢那些少年的腿,看那些少年是否站的够稳。而希尔曼则是朝北边那群六七岁的孩童走去,那些孩童们立即紧张了起来。“不好,大魔头来了。”一名大眼睛,叫‘哈德利’的金发孩童低声说道。希尔曼步入这一群孩童中央,看着这些孩子,希尔曼脸上冷漠,可是心中却感叹:“这些孩子实在太小了,无论是体能上或者心智上还远远不够,对他们的要求也不能太高。不过身体锻炼,还是从小培养的好,从小认真锻炼,将来上战场活命的机会才能更大。”而教导小孩子……诱导他们,吸引他们,是最有效的方法!强迫只能起反作用!“一个个站好了。”希尔曼冷哼一声。顿时一个个孩童挺起胸膛,目视前方。希尔曼嘴角升起一丝笑意,随后便走到最前面,脱去了身上的背心,身上那些肌肉线条让那些小孩子们一个个睁大了眼睛,连中央、南边的少年们也都羡慕地看着希尔曼身上的肌肉。除了那几近完美的肌肉线条,希尔曼那裸露的上半身有着刀痕、剑痕,各种伤痕足有数十道,所有的孩子都眼睛放光地看着那些伤痕。刀痕、剑痕,这是男人的勋章!他们的心底对于希尔曼都是非常崇拜的。希尔曼,一位伟大的六级战士,在生与死之中磨练出来的勇士";
}

创建索引:

@SpringBootTest
public class AddSource {private static final String index = "sms-logs-index";private static final String type = "sms-logs-type";@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testpublic void createIndex() throws  Exception{// 1.准备关于索引的settingSettings.Builder settings = Settings.builder().put("number_of_shards", 3).put("number_of_replicas", 1);// 2.准备关于索引的mappingXContentBuilder mappings = JsonXContent.contentBuilder().startObject().startObject("properties").startObject("corpName").field("type", "keyword").endObject().startObject("createDate").field("type", "date").endObject().startObject("fee").field("type", "integer").endObject().startObject("ipAddr").field("type", "ip").endObject().startObject("longCode").field("type", "keyword").endObject().startObject("mobile").field("type", "keyword").endObject().startObject("operatorId").field("type", "integer").endObject().startObject("province").field("type", "keyword").endObject().startObject("replyTotal").field("type", "integer").endObject().startObject("sendDate").field("type", "date").endObject().startObject("smsContent").field("type", "text").field("analyzer", "ik_max_word").endObject().startObject("state").field("type", "integer").endObject().endObject().endObject();// 3.将settings和mappings 封装到到一个Request对象中CreateIndexRequest request = new CreateIndexRequest(index).settings(settings).mapping(type,mappings);// 4.使用restHighLevelClient去连接ESCreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);System.out.println("response:" + JSON.toJSONString(response));}
}

添加文档数据:

@SpringBootTest
public class AddSource {private static final String index = "sms-logs-index";private static final String type = "sms-logs-type";@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testpublic void  bulkCreateDoc() throws  Exception{// 1.准备多个json 对象String longcode = "1008687";String mobile ="138340658";List<String> companies = new ArrayList<>();companies.add("腾讯课堂");companies.add("阿里旺旺");companies.add("海尔电器");companies.add("海尔智家公司");companies.add("格力汽车");companies.add("苏宁易购");List<String> provinces = new ArrayList<>();provinces.add("北京");provinces.add("重庆");provinces.add("上海");provinces.add("晋城");BulkRequest bulkRequest = new BulkRequest();for (int i = 1; i < 11 ; i++) {Thread.sleep(1000);SmsLogs s1 = new SmsLogs();s1.setId(i);s1.setCreateDate(new Date());s1.setSendDate(new Date());s1.setLongCode(longcode + i);s1.setMobile(mobile + 2 * i);s1.setCorpName(companies.get(i % 5));s1.setSmsContent(SmsLogs.doc.substring((i - 1) * 100,i * 100));s1.setState(i % 2);s1.setOperatorId(i % 3);s1.setProvince(provinces.get(i % 4));s1.setIpAddr("127.0.0." + i);s1.setReplyTotal(i * 3);s1.setFee(i * 6);String json1  = JSON.toJSONString(s1);bulkRequest.add(new IndexRequest(index,type,s1.getId().toString()).source(json1, XContentType.JSON));System.out.println("数据" + i + json1);}// 3.restHighLevelClient 执行BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);// 4.输出结果System.out.println(JSON.toJSONString(responses.getItems()));}
}

查看结果:

2、term查询

term 查询是代表完全匹配,搜索之前不会对你搜索的关键字进行分词,对你的关键字去文档分词库中去匹配内容。

kibana中实现:

# term查询(类似 MySql 中:where province = 北京)
POST /sms-logs-index/sms-logs-type/_search
{"from":0,# 当前页"size":1,# 每一页显示条数"query": {"term": { # term条件"province": {"value": "北京" # 值}}}
}

java实现方式:

@SpringBootTest
public class QueryTest {private static final String index = "sms-logs-index";private static final String type = "sms-logs-type";@Autowiredprivate RestHighLevelClient restHighLevelClient;@Testpublic void term() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//分页参数当前页builder.from(0);//分页参数每页显示多少条builder.size(5);//term查询builder.query(QueryBuilders.termQuery("province","北京"));//将条件放入request中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据(数据在hits里面)SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}}
}

3、terms查询

terms 和 term 的查询机制是一样的,都不会将指定的查询关键字进行分词,直接去分词库中匹配,找到相应文档内容。

terms 是针对在一个字段包含多个值的时候使用,类似 MySql 中 in 查询方式

kibana中实现:

# terms查询 (类似 where province in('北京','上海'))
POST /sms-logs-index/sms-logs-type/_search
{"from": 0,"size": 10, "query": {"terms": {"province": ["北京","上海"]}}
}

java实现方式:

@Test
public void terms() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//分页参数当前页builder.from(0);//分页参数每页显示多少条builder.size(10);//terms查询builder.query(QueryBuilders.termsQuery("province","北京","上海"));//将条件放入request中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据(数据在hits里面)SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

4、match查询

match查询属于高层查询,会根据查询的字段类型不一样,采用不同的查询方式。

  • 查询的内容如果是日期或者数值类型,会将你基于的字符串查询内容转换为日期或者数值对待。
  • 如果查询的内容是一个不能被分词的内容(keyword),match查询不会对你指定的查询关键字进行分词。
  • 如果查询的内容是一个可以被分词的内容(text),match会将你指定的查询内容根据一定方式进行分词,去分词库中匹配指定的内容。
  • match查询,底层实际就是多个term查询,将多个term查询的结果封装到一起。

kibana中实现:

# match查询,指定一个Field作为筛选条件
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match": {"smsContent": "最满意" # 会进行分词}}
}

java实现方式:

@Test
public void t4() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.matchQuery("smsContent","最满意"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

5、match_all查询

查询全部内容,不指定任何查询条件

kibana中实现:

# match_all查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match_all": {}}
}

java实现方式:

@Test
public void t3() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.matchAllQuery());//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

6、布尔match查询

基于一个 Field 匹配的内容,采用 and 或者 or 方式连接

kibana中实现:

# 布尔match查询 and方式连接
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match": {"smsContent": {"query": "团队 最","operator": "and" # 查询出的内容既包含团队又包含最}}}
}# 布尔match查询 or方式连接
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match": {"smsContent": {"query": "团队 最","operator": "or"  # 查询出的内容包含团队或者包含最}}}
}

java实现方式:

@Test
public void t5() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//and方式连接builder.query(QueryBuilders.matchQuery("smsContent","团队 最").operator(Operator.AND));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}@Test
public void t6() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//or方式连接builder.query(QueryBuilders.matchQuery("smsContent","团队 最").operator(Operator.OR));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

7、multiMatch查询

match 针对一个 Field 做检索,multi_match 针对多个 Field 进行检索。多个 Field 对应一个 text。

kibana中实现:

# multi_match查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"multi_match": {"query": "上",        # 指定text"fields": ["province","smsContent"]       # 指定 Fields}}
}

java实现方式:

@Test
public void t7() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.multiMatchQuery("上","province","smsContent"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

8、id查询

根据文档id进行查询

kibana中实现:

# 索引/类型/文档id
GET /sms-logs-index/sms-logs-type/1

java实现方式:

@Test
public void t8() throws IOException {//创建GetRequest对象GetRequest request = new GetRequest(index,type,"1");//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.multiMatchQuery("上","province","smsContent"));//执行查询GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);//提取数据Map<String, Object> hits = response.getSource();System.out.println(hits);
}

9、ids查询

根据多个id查询,类似MySql中的where id in(id1,id2,id…)

kibana中实现:

POST /sms-logs-index/sms-logs-type/_search
{"query": {"ids": {"values": ["1","2","3"]}}
}

java实现方式:

@Test
public void t9() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.idsQuery().addIds("1","2","3"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

10、prefix查询

前缀查询,可以通过一个关键字去指定一个 Field 的前缀,从而查询到指定的文档数据。

kibana中实现:

# prefix 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"prefix": {"corpName": {"value": "阿里"}}}
}

java实现方式:

@Test
public void t10() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.prefixQuery("corpName","阿里"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

11、fuzzy查询

模糊查询,我们输入字符的大概,ES 就可以去根据输入的内容大概去匹配一下结果。

kibana中实现:

# fuzzy 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"fuzzy": {"corpName": {"value": "海尔电气","prefix_length": 2        # 指定前面几个字符是不允许出现错误的}}}
}

java实现方式:

@Test
public void t11() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.fuzzyQuery("corpName","海尔电气").prefixLength(2));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

12、wildcard查询

统配查询,类似 MySql 中的 like 查询,可以在查询时,在字符串中指定通配符 * 和占位符 ?

kibana中实现:

# wildcard 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"wildcard": {"corpName": {"value": "海尔*"       # * 表示匹配所有,? 表示占位一个}}}
}

java实现方式:

@Test
public void t12() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.wildcardQuery("corpName","海尔?"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

13、range查询

范围查询,只针对数值类型,对某一个 Field 进行大于或者小于的范围指定。

kibana中实现:

# range 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"range": {"fee": {"gt": 10,      # gt:大于,gte:大于等于"lt": 20     # lt:小于,lte:小于等于}}}
}

java实现方式:

 @Test
public void t13() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.rangeQuery("fee").gt(10).lt(20));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

14、regexp查询

正则查询,通过编写的正则表达式去匹配内容

prefix,fuzzy,wildcard 和 regexp 查询效率相对 term 和 match 比较低,要求效率比较高时,避免去使用

kibana中实现:

# regexp 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"regexp": {"mobile": "138[0-9]{8}"}}
}

java实现方式:

@Test
public void t14() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.regexpQuery("mobile","138[0-9]{8}"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

15、深分页Scroll

ES 对 from + size是有限制的,from 和 size二者之和不能超过 1w

原理:

from + size 在ES查询数据的方式:

  • 第一步先将用户指定的关键词进行分词。
  • 第二步将词汇去分词库中进行检索,得到多个文档的id。
  • 第三步去各个分片中去拉取指定的数据。耗时较长
  • 第四步将数据根据score进行排序。耗时较长
  • 第五步根据from的值,将查询到的数据舍弃一部分。
  • 第六步返回结果。

Scroll + size 在ES查询数据的方式:

  • 第一步先将用户指定的关键词进行分词。
  • 第二步将词汇去分词库中进行检索,得到多个文档的id。
  • 第三步将文档的id存放在ES的上下文中。
  • 第四步根据你指定的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除。
  • 第五步如果需要下一页数据,直接去ES的上下文中,找后续内容。
  • 第六步循环第四步和第五步。

缺点:Scroll查询方式,不适合做实时的查询

kibana中实现:

# 执行scroll查询,返回第一页数据,并且将文档id信息存放在ES上下文中,指定生存时间60s
POST /sms-logs-index/sms-logs-type/_search?scroll=60s
{"query": {"match_all": {}}, "size": 2,"sort": [                # 排序{"fee": {"order": "desc"}}]
}# 根据scroll查询下一页数据
POST /_search/scroll
{"scroll_id":"<根据第一步得到的scroll_id去指定>","scroll":"<scroll信息的生存时间>"
}# 删除scroll在ES上下文中的数据
DELETE /_search/scroll/scroll_id

java实现方式:

@Test
public void t15() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定scroll信息,生存时间request.scroll(TimeValue.timeValueMinutes(1L));//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.size(4);builder.sort("fee", SortOrder.DESC);builder.query(QueryBuilders.matchAllQuery());request.source(builder);//获取返回结果scrollId,sourceSearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);String scrollId = response.getScrollId();System.out.println("----首页----");for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}while (true) {//循环 - 创建SearchScrollRequestSearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);//指定scrollId的生存时间scrollRequest.scroll(TimeValue.timeValueMinutes(1L));//执行查询获取返回结果SearchResponse scrollResponse = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);//判断是否查询到了数据,输出SearchHit[] hits = scrollResponse.getHits().getHits();if (hits != null && hits.length > 0){System.out.println("----下一页----");for (SearchHit hit : hits) {System.out.println(hit.getSourceAsMap());}} else {//判断没有查询到数据就退出循环System.out.println("----结束----");break;}}//创建ClearScrollRequst对象ClearScrollRequest clearRequest = new ClearScrollRequest();//指定scrollIdclearRequest.addScrollId(scrollId);//删除scrollIdClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearRequest, RequestOptions.DEFAULT);//输出System.out.println("是否删除成功:" + clearScrollResponse.isSucceeded());
}

16、delete-by-query

根据 term,match 等查询方式去删除大量的文档

如果需要删除的内容,是 index 下的大部分数据,此时不建议删除,推荐创建一个全新的 index,将保留的文档内容,添加到全新的索引中

kibana中实现:

# delete-by-query
POST /sms-logs-index/sms-logs-type/_delete_by_query
{"query":{"range":{"fee":{"lt":20}}}
}

java实现方式:

@Test
public void t16() throws IOException {//创建DeleteByQueryRequestDeleteByQueryRequest request = new DeleteByQueryRequest(index).types(type);//指定检索的条件request.setQuery(QueryBuilders.rangeQuery("fee").lt(20));//执行删除BulkByScrollResponse response = restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);//输出结果System.out.println(response.toString());
}

17、复合查询之bool查询

复合过滤器,将你的多个查询条件,以一定的逻辑组合在一起。

  • must:所有的条件,用 must 组合在一起,表示 and 的意思。
  • must_not:将 must_not 中的条件,全部都不能匹配,表示 not 的意思。
  • should:所有的条件,用 should 组合在一起,表示 or 的意思。

kibana中实现:

# 查询省份为北京或者上海
# 查询公司不是海尔电器
# smsContent中包含团队和最
# bool查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"bool": {"should": [{"term": {"province": {"value": "北京"}}},{"term": {"province": {"value": "上海"}}}],"must_not": [{"term": {"corpName": {"value": "海尔电器"}}}],"must": [{"match": {"smsContent": "团队"}},{"match": {"smsContent": "最"}}]}}
}

java实现方式:

@Test
public void t17() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolQuery.should(QueryBuilders.termQuery("province","北京"));boolQuery.should(QueryBuilders.termQuery("province","上海"));boolQuery.mustNot(QueryBuilders.termQuery("corpName","海尔电器"));boolQuery.must(QueryBuilders.matchQuery("smsContent","团队"));boolQuery.must(QueryBuilders.matchQuery("smsContent","最"));builder.query(boolQuery);//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

18、复合查询之boosting查询

boosting 查询可以帮助我们去影响查询后的 score。

  • positive:只有匹配上 positive 的查询的内容,才会被放到返回的结果集中。
  • negative:只有匹配上和 positive 并且也匹配上了 negative,就可以降低这样的的文档 score。
  • negative_boost:指定系数,必须小于 1.0。

关于查询时,分数是如何计算的:

  • 搜索关键字在文档中出现的频次越高,分数就越高。
  • 指定的文档内容越短,分数就越高。
  • 在搜索时,指定的关键字也会被分词,这个分词的内容,被分词库匹配的个数越多,分数越高。

kibana中实现:

# boosting查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"boosting": {"positive": {"match": {"smsContent": "中年人"}},"negative": {"match": {"smsContent": "希尔曼"}},"negative_boost": 0.5}}
}

java实现方式:

@Test
public void t18() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件,并指定系数SearchSourceBuilder builder = new SearchSourceBuilder();BoostingQueryBuilder boostingQuery = QueryBuilders.boostingQuery(QueryBuilders.matchQuery("smsContent", "中年人"),QueryBuilders.matchQuery("smsContent", "希尔曼")).negativeBoost(0.5f);//将boostingQuery放到builder中builder.query(boostingQuery);//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

19、filter查询

query查询:根据查询条件,去计算文档的匹配度得到一个分数,并且根据分数进行排序,不会做缓存的。

filter查询:根据查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存。

kibana中实现:

# filter查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"bool": {"filter": [{"term": {"corpName": "阿里旺旺"}},{"range":{"fee":{"gt":10}}}]}}
}

java实现方式:

@Test
public void t19() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件,并指定系数SearchSourceBuilder builder = new SearchSourceBuilder();BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolQuery.filter(QueryBuilders.termQuery("corpName","阿里旺旺"));boolQuery.filter(QueryBuilders.rangeQuery("fee").gt(10));//将boolQuery放到builder中builder.query(boolQuery);//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//转为map集合Map<String, Object> result = hit.getSourceAsMap();System.out.println(result);}
}

20、高亮查询

高亮查询:就是将要查询的关键字,以一定的样式展示给用户,让用户知道为什么这个结果被检索出来。

高亮展示的数据,本身就是文档中的一个 Field,单独将 Field 以 highlight 的形式返回给你。

ES提供了一个 highlight 属性,和 query 同级别的。

  • fragment_size:指定高亮数据展示多少个字符(默认100个)
  • pre_tags:指定前缀标签,比如
  • post_tags:指定后缀标签,比如
  • fields:指定哪几个 Field 以高亮形式返回

kibana中实现:

# highlight查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match": {"smsContent": "不被人瞧不起"}},"highlight": {"fields": {"smsContent": {}},"pre_tags": "<font color='red'","post_tags": "</font>","fragment_size": 10}
}

java实现方式:

@Test
public void t20() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件(高亮)SearchSourceBuilder builder = new SearchSourceBuilder();//指定查询条件builder.query(QueryBuilders.matchQuery("smsContent","不被人瞧不起"));//指定高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("smsContent",10).preTags("<font color='red'>").postTags("</font>");//将highlightBuilder放到builder中builder.highlighter(highlightBuilder);//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//提取数据SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {System.out.println(hit.getHighlightFields().get("smsContent"));}
}

21、聚合查询

ES的聚合查询和MySQL的聚合查询类似,ES的聚合查询相比MySQL更强大的多,ES提供的统计数据的方式多种多样。

ES聚合查询的RESTful语法:

POST /index/type/_search
{"aggs": {"名字(agg)": {"agg_type": {"属性":"值"}}}
}

1、去重计数查询

去重计数即 Cardinality,第一步先将返回的文档中的一个指定的 Field 进行去重,统计一共有多少一条

kibana中实现:

# 去重计数
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"cardinality": {"field": "province"}}}
}

java实现方式:

@Test
public void t21() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//指定使用的聚合方式builder.aggregation(AggregationBuilders.cardinality("agg").field("province"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//获取返回结果Cardinality agg = response.getAggregations().get("agg");System.out.println(agg.getValue());
}

2、范围统计

统计一定范围内出现的文档个数,比如:针对某一个 Field 的值在 0-100,100-200,200-300之间文档出现的个数分别是多少。

范围统计可以针对普通的数据,时间类型,ip类型都可以做相应的统计。

range,date_range,ip_range

kibana中实现:

# 数值方式范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"range": {"field": "fee","ranges": [{"to": 20},{"from": 20,       # 包含当前值"to": 50       # 不包含当前值},{"from": 50}]}}}
}
# 时间范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"date_range": {"field": "createDate","format": "yyyy", "ranges": [{"to": 2000},{"from": 2000}]}}}
}
# ip范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"ip_range": {"field": "ipAddr","ranges": [{"to": "127.0.0.10"},{"from": "127.0.0.15"}]}}}
}

java实现数值范围统计方式:

@Test
public void t22() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//指定使用的聚合方式builder.aggregation(AggregationBuilders.range("agg").field("fee").addUnboundedTo(20).addRange(20,50).addUnboundedFrom(50));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//获取返回结果Range agg = response.getAggregations().get("agg");for (Range.Bucket bucket : agg.getBuckets()) {String key = bucket.getKeyAsString();Object from = bucket.getFrom();Object to = bucket.getTo();long docCount = bucket.getDocCount();System.out.println(String.format("key:%s,from:%s,to:%s,docCount:%s",key,from,to,docCount));}
}

22、统计聚合查询

统计聚合查询即(extended_stats),可以查询指定 Field 的最大值、最小值、平均值、平方和…

kibana中实现:

# 统计聚合查询
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"extended_stats": {"field": "fee"}}}
}

java实现方式:

@Test
public void t23() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest(index).types(type);//指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//指定使用的聚合方式builder.aggregation(AggregationBuilders.extendedStats("agg").field("fee"));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//获取返回结果ExtendedStats agg = response.getAggregations().get("agg");double max = agg.getMax();double min = agg.getMin();System.out.println("最大值:" + max + "-----最小值:" + min);
}

其他的聚合查询方式查看官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/index.html

23、地图经纬度搜索

ES中提供了一个数据类型 geo_point,这个类型就是用来存储经纬度的。

kibana中实现:

# 创建一个索引,指定一个 name,location
PUT /map
{"settings": {"number_of_shards": 5, "number_of_replicas": 1}, "mappings": {"map": {"properties": {"name": {"type": "text"},"location": {"type": "geo_point"}}}}
}# 添加经纬度
PUT /map/map/1
{"name": "天安门","location": {"lon": 116.403981,"lat": 39.914492}
}PUT /map/map/2
{"name": "海淀公园","location": {"lon": 116.302509,"lat": 39.991152}
}PUT /map/map/3
{"name": "北京动物园","location": {"lon": 116.343184,"lat": 39.947468}
}

1、ES的地图检索方式

  • geo_distance:直线距离检索方式
  • geo_bounding_box:以两个点确定一个矩形,获取在矩形内的全部数据
  • geo_polygon:以多个点,确定一个多边形,获取多边形内的全部数据

kibana中实现:

# geo_distance
POST /map/map/_search
{"query": {"geo_distance": {"location": {     # 确定一个点的坐标"lon": 116.433733,"lat": 30.908404},"distance": 2000,           # 确定半径"distance_type": "arc"    # 指定形状为圆形}}
}
# geo_bounding_box
POST /map/map/_search
{"query": {"geo_bounding_box": {"location": {"top_left": {      # 左上角坐标点"lon": 116.326943,"lat": 30.95489},"bottom_right": {      # 右下角坐标点"lon": 116.347783,"lat": 30.939281}}}}
}
# geo_polygon
POST /map/map/_search
{"query": {"geo_bounding_box": {"location": {"points": [        # 指定多个点确定一个多边形{"lon": 116.298916,"lat": 39.99878},{"lon": 116.29561,"lat": 39.972576},{"lon": 116.327661,"lat": 30.984739}]}}}
}

java实现方式:

@Test
public void t24() throws IOException {//创建SearchRequest对象SearchRequest request = new SearchRequest("map").types("map");//指定检索方式SearchSourceBuilder builder = new SearchSourceBuilder();List<GeoPoint> points = new ArrayList<>();//维度,经度与kibana中相反points.add(new GeoPoint(39.99878,116.298916));points.add(new GeoPoint(39.972576,116.29561));points.add(new GeoPoint(30.984739,116.327661));builder.query(QueryBuilders.geoPolygonQuery("location",points));//将条件放入request对象中request.source(builder);//执行查询SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//获取返回结果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}

ElasticSearch6.5.4快速入门相关推荐

  1. (十一) ELK快速入门

    本文为学习笔记,主要用于记录本人学习过程.部分内容为转载!!!!. ELK快速入门一-基本部署 ELK简介 什么是ELK?通俗来讲,ELK是由Elasticsearch.Logstash.Kibana ...

  2. 零基础快速入门SpringBoot2.0教程 (三)

    一.SpringBoot Starter讲解 简介:介绍什么是SpringBoot Starter和主要作用 1.官网地址:https://docs.spring.io/spring-boot/doc ...

  3. 【Elastic Stack上】Elastic Search快速入门,让你对ELK日志架构不再困惑

    课程介绍 Elastic Stack简介 Elasticsearch的介绍与安装 Elasticsearch的快速入门 Elasticsearch的核心讲解中文分词 全文搜索 Elasticsearc ...

  4. Shiro第一个程序:官方快速入门程序Qucickstart详解教程

    目录 一.下载解压 二.第一个Shiro程序 1. 导入依赖 2. 配置shiro配置文件 3. Quickstart.java 4. 启动测试 三.shiro.ini分析 四.Quickstart. ...

  5. 计算机入门新人必学,异世修真人怎么玩?新手快速入门必备技巧

    异世修真人怎么快速入门?最近新出来的一款文字修仙游戏,很多萌新不知道怎么玩?进小编给大家带来了游戏新手快速入门技巧攻略,希望可以帮到大家. 新手快速入门攻略 1.开局出来往下找婆婆,交互给点钱,旁边有 ...

  6. Spring Boot 2 快速教程:WebFlux 快速入门(二)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  7. Apache Hive 快速入门 (CentOS 7.3 + Hadoop-2.8 + Hive-2.1.1)

    2019独角兽企业重金招聘Python工程师标准>>> 本文节选自<Netkiller Database 手札> 第 63 章 Apache Hive 目录 63.1. ...

  8. 《iOS9开发快速入门》——导读

    本节书摘来自异步社区<iOS9开发快速入门>一书中的目录,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众号查看 目 录 前 言 第1章 iOS ...

  9. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 序

    BIML 101 - BIML 快速入门教程 做大数据的项目,最花时间的就是数据清洗. 没有一个相对可靠的数据,数据分析就是无木之舟,无水之源. 如果你已经进了ETL这个坑,而且预算有限,并且有大量的 ...

最新文章

  1. DPU加持下的阿里云如何做加密计算?
  2. windows x64 build c++ poco库
  3. vue 递归组件多级_Vue递归组件实现树形结构菜单
  4. c语言怎么让字母倒序排列尼,如何倒序单词顺序输出 ? 我是没辙了
  5. vue改变页面顶部浏览器标题栏图标
  6. js(jQuery)获取时间的方法及常用时间类
  7. 前端学习(2028)vue之电商管理系统电商系统之展示物流进度
  8. android 自定义横向堆积柱形图,MPAndroidChart项目实战(八)——自定义分段堆积柱状图...
  9. SQL模糊查询特殊符号应用及详细案例说明
  10. 单级离心压缩机行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  11. ActiveMQ学习-Network connectors JAVA代码实现
  12. Docker-07:Docker网络管理
  13. 淘晶驰串口屏下载工程慢怎么办
  14. 什么是BLOB URL,为什么要使用它?
  15. 个人的OKR该怎么写?
  16. afx是什么意思呀,什么时候要include呢,这个头文件的作用是??
  17. LDAP服务器不支持chap认证,终端使用EIA进行PEAP-GTC认证失败的原因分析
  18. 安卓APP源码和设计报告——小说阅读器
  19. Cisco与H3C交换机互联的小风波
  20. 超声波测距模块HC-SR04详解(基于51单片机)

热门文章

  1. amp;#9733;平衡法则在生活中的应用
  2. python新式类和旧式类的区别_浅谈python新式类和旧式类区别
  3. vue-devtools工具的安装和使用
  4. NB无信号以及无法连接网络问题分析及解决
  5. cmake:通过CMAKE_CXX_COMPILE_FEATURES判断编译器是否支持C++11
  6. Linux基础,系统概叙与虚拟机搭建+CentOS系统安装(建议收藏)
  7. WdatePicker时间日期插件总结
  8. Eclipse解决输入简体中文汉字出现繁体字的问题和Eclipse中Ctrl+Shift+F整理代码格式的无效问题
  9. iOS 数据持久化方式 - 归档 反归档
  10. WPF打开摄像头拍照