ElasticSearch
是非关系型数据库
官网: www.elastic.co,是基于Lucene的搜索服务器
关系型数据库查询的弊端 :
性能低、功能弱 ES是弥补这一缺点而诞生的
1.性能低 模糊查询 一条条的遍历
2.功能弱 存储的都是字符串 不能在商品信息字段中 查询出 含有华为或手机的
倒排索引
将各个文档中的内容进行分词、形成词条。然后记录词条和数据的唯一标识的对应关系,形成的产物。是一个散列图
存储原理
1.在index索引库中 生成数据表,即把所有的文档都进行分词且把相同的值放入value,供用户调用
2.由于数据过于庞大,就设置了树形结构来存储数据,以提升效率
3.查询时会将用户输入的词语先进行分词处理,再查找对应的文档
ES概念
1.定义
一个分布式 高扩展 高实时的搜索与数据分析搜索引擎。
是对Lucene的升级,基于RESTful风格的web接口,通过http的请求就可以对es进行操作,开源、流行的企业级搜搜引擎
2.应用场景
1.海量数据查询 数据量小不需要使用
2.日志数据分析
3.实时数据分析
3.Mysql与ES区别
ES和mysql 分工不同
mysql负责数据存储 有事务
es负责数据搜索 无事务 删除则无法恢复
ES也可以当作数据库 但是要用在不使用事务的情况下
ES组成❤️
索引 index # 索引库
文档 document # mysql的row 一行数据 最小数据单元
字段 field # mysql的column 列字段名
倒排索引 # index中的 key对应的value值
type
1. 版本7以后默认 _doc 此概念以弱化
2. 版本6 index只能有一种type
3. 版本5 index可以有多种type
例:
#索引 #内置指令
POST person/_doc/2
{ # name、address是field字段
"name":"wangzhen",# wangzhen、cq 是一个文档数据
"address":"cq"
}
#mapping 只是映射 定义每个field的类型 与表结构类似
RESTful访问
定义接口的规范,满足这些规范的应用程序或设计就是RESTful
1.基于http协议
2.使用xml或者json来定义
3.每个url表示一种资源
GET 查询
POST 添加/更新
PUT 添加/更新
DELETE 删除
UPDATE 更新
Linux启动ES
安装看安装文档
启动es
#暂时关闭防火墙
systemctl stop firewalld
# 或者
#永久设置防火墙状态
systemctl enable firewalld.service #打开防火墙永久性生效,重启后不会复原
systemctl disable firewalld.service #关闭防火墙,永久性生效,重启后不会复原
su 用户名 # 切换到其他用户启动 不允许root用户启动
cd /opt/elasticsearch-7.4.0/bin
./elasticsearch #启动
启动kibana
# 切换到kibana的bin目录
cd /opt/kibana-7.4.0-linux-x86_64/bin
# 启动
./kibana --allow-root
访问ES==?==
默认端口9200
添加索引
PUT http://ip:9200(端口)/索引名称
查询索引
GET _all 查询所有
删除索引
DELETE
关闭/打开索引
POST http://ip:9200(端口)/索引名称/_close/_open
指令
默认的 GET PUT DELETE POST 四种
指令名 | 作用 |
---|---|
_search | 查询所有索引 |
_doc/ID号 | 按照id来精确增删改查 |
_analyze | ik分词器,指定分词类型 默认standard |
_bulk | 批量操作 |
ES数据类型
# 简单数据类型
(聚合:将数据聚合起来形成类似于mysql的聚合函数)
1.字符串:
text 字符串 类String 分词,不支持聚合 (华为、手机)
keyword 字符串 类String 不分词,支持聚合 (华为手机)
2.数值:
long、ingeter、short、byte、double、
float : 单精度32位IEEE
half_float : 半精度16位IEEE
scaled_float :由a支持的有限浮点数long
3.布尔
4.二进制 binary 二进制格式存储到index (了解)
5.范围类型 range
6.日期 date
# 复杂数据类型
1.数组 []
2.对象 {}
映射
作用:给索引设置字段、添加字段
mapping:是用于映射文档字段、index属性的功能
字段属性
- type:指定类型
- analyer:指定存储分词器
- search_analyzer:指定搜索时的分词器
- enabled:是否建立索引
- store:是否可以排序
不能用于删除
GET person # 查询
GET person/_mapping # 查询映射
PUT person # 创建
# 创建时映射属性name、age 制作数据结构 含有 name 类型是keykeyword的字符串
PUT person/_mapping
{
"properties":{
"name":{
"type":"keykeyword"
},
"age":{
"type":"integer"
}
}
}
# 在基础上添加映射字段address
PUT person/_mapping
{
"properties":{
"address":{
"type":"text"
}
}
}
# 如果添加时显示磁盘空间不足 则可以把这个设置为false就可以添加 但是每次添加时都要执行
PUT 索引名/_settings
{
"index.blocks.read_only_allow_delete":false
}
添加文档
作用: 为索引添加一条数据
(添加一行数据) 分为指定id/不指定id 不指定会默认创建一个随机id
不指定id 查询 只能使用post的restful
id作为查询时的唯一标识
# 添加一条文档 (已有person索引,就可以添加文档)
# DELETE 删除文档
POST person/_doc/2
{
"name":"wangzhen",
"age":32,
"address":"cq"
}
分词器使用
注意:在创建索引时,如果某字段需要创建分词,要指定分词类型
1.三种分词方式
#分为三种方式 ES默认以standard进行分词!!
1.standard 按照每个字进行分词
2.ik_smart 粗粒度
3.ik_max_word 细粒度 粗粒度的运行速度更快
# 使用分词器
GET _analyze
{
"analyzer": "standard",
"text":"北京天安门门"
}
# 添加person索引时 同时修改adress字段的分词器
PUT person
{
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"adress":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
2.两种分词查询
# 使用term分词
# 作用: 查询的条件字符串与词条完全匹配
GET person/_search
{
"query": {
"term": {
"adress": {
"value": "手机"
}
}
}
}
# 使用match分词
# 作用: 查询的条件字符串会在倒排中查询出对应的词条再进行并集查询(华为手机 词条:1.华为 2.手机 --> 结果会把两个词条的结果都返回)
GET person/_search
{
"query": {
"match": {
"adress": "华为手机"
}
}
}
}
spring整合ES❤️
基础步骤
ES在虚拟机中的启动方式
启动ES
#暂时关闭防火墙
systemctl stop firewalld
#永久设置防火墙状态
systemctl enable firewalld.service #打开防火墙永久性生效,重启后不会复原
systemctl disable firewalld.service #关闭防火墙,永久性生效,重启后不会复原
su 用户名 # 切换到新用户启动,不允许root用户启动
cd /opt/elasticsearch-7.4.0/bin
./elasticsearch #启动
启动Kibanna
# 切换到kibana的bin目录
cd /opt/kibana-7.4.0-linux-x86_64/bin
# 启动
./kibana --allow-root
操作步骤
1.自动注入,获取client对象
2.创建操作索引对象 #CreateIndex创建索引、 DeleteIndex删除、 GetIndex查询索引 如:CreateRequest("索引名")
3.使用client对象 获取 IndicesClient执行对象
3.执行对象调用增删改查对应的方法 获得响应对象 #要传入对象、 RequestOptions.DEFAULT 两个条件
create、delete、get
如果要操作文档,则是直接使用client对象
index 增/改 文档 调用时方法中要指定该对象:XContentType.JSON
get 查询
delete 删除 查询 删除 指定该对象:RequestOptions.DEFAULT
1.导入依赖
<!--引入es的坐标-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.4.0</version>
</dependency>
<!--导入测试类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--需要添加此依赖 否则有可能不能启动-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.配置
@Configuration //定义为核心配置类
@ConfigurationProperties(prefix = "elasticsearch") //读入host和port的yml配置文件
public class ElasticSearchConfig {
private String host;
private int port; //9200
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
//存入bean中 由spring管理RestHighLevelClient对象
@Bean
public RestHighLevelClient client(){
//传入IP、端口、指定协议
return new RestHighLevelClient(RestClient.builder(new HttpHost(host, port, "http")
));
}
}
3.创建索引
//由于已经配置过该对象,所以可以直接注入
//下面的所有操作都需要用到此对象
@Autowired
private RestHighLevelClient client;
//1.使用client获取操作索引的对象
IndicesClient indicesClient = client.indices();
//2.具体操作,获取返回值
CreateIndexRequest createRequest = new CreateIndexRequest("itheima");
CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);
//2.1 设置mappings,为这个索引添加字段
//从kibana中写好粘贴
String mapping = "{\n" +
" \"properties\" : {\n" +
" \"address\" : {\n" +
" \"type\" : \"text\",\n" +
" \"analyzer\" : \"ik_max_word\"\n" +
" },\n" +
" \"age\" : {\n" +
" \"type\" : \"long\"\n" +
" },\n" +
" \"name\" : {\n" +
" \"type\" : \"keyword\"\n" +
" }\n" +
" }\n" +
" }";
//2.2 为索引绑定字段
createRequest.mapping(mapping,XContentType.JSON);
//3.根据返回值判断结果
System.out.println(response.isAcknowledged());
4.查询索引
可以判断是否存在
IndicesClient indices = client.indices();
GetIndexRequest getReqeust = new GetIndexRequest("itcast");
boolean exists = indices.exists(getReqeust, RequestOptions.DEFAULT); //判断是否存在
//查看结果
System.out.println(exists);
//
GetIndexResponse response = indices.get(getReqeust, RequestOptions.DEFAULT);
//获取结果
//此处是map对象 遍历要使用map的两种遍历方式
Map<String, MappingMetaData> mappings = response.getMappings();
for (String key : mappings.keySet()) {
System.out.println(key+":" + mappings.get(key).getSourceAsMap());
}
5.删除索引
IndicesClient indices = client.indices();
DeleteIndexRequest deleteRequest = new DeleteIndexRequest("itheima");
AcknowledgedResponse response = indices.delete(deleteRequest, RequestOptions.DEFAULT);
6.添加文档的两种方式
与其他不一样 是使用client对象调用index方法直接添加数据
//使用map
Map data = new HashMap();
data.put("address","北京昌平");
data.put("name","大胖");
data.put("age",20);
//1.获取操作文档的对象
IndexRequest request = new IndexRequest("itcast").id("1").source(data);
//添加数据,获取结果
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
//====================================================================
//====================================================================
//====================================================================
//使用对象
Person p = new Person();
p.setId("2");
p.setName("小胖2222");
p.setAge(30);
p.setAddress("陕西西安");
//将对象转为json
String data = JSON.toJSONString(p);
//1.获取操作文档的对象
//该XContentType.JSON是使用的fastjson来转换为map
IndexRequest request = new IndexRequest("itcast").id(p.getId()).source(data,XContentType.JSON);
//添加数据,获取结果
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
//打印响应结果
System.out.println(response.getId());
7.根据id查询文档
GetRequest getReqeust = new GetRequest("itcast","1");
//getReqeust.id("1");
GetResponse response = client.get(getReqeust, RequestOptions.DEFAULT);
//获取数据对应的json
System.out.println(response.getSourceAsString());
批量操作
1.批量增删改ES文档
public void testBulk() throws IOException {
//创建bulkrequest对象,整合所有操作
BulkRequest bulkRequest = new BulkRequest();
//添加对应操作
//1. 删除1号记录
DeleteRequest deleteRequest = new DeleteRequest("person","1");
bulkRequest.add(deleteRequest);
//2. 添加6号记录
Map map = new HashMap();
map.put("name","六号");
IndexRequest indexRequest = new IndexRequest("person").id("6").source(map);
bulkRequest.add(indexRequest);
Map map2 = new HashMap();
map2.put("name","三号");
//3. 修改3号记录 名称为 “三号”
UpdateRequest updateReqeust = new UpdateRequest("person","3").doc(map2);
bulkRequest.add(updateReqeust);
//执行批量操作
BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);//统一使用add已经将数据封装到bulk对象中
RestStatus status = response.status();
System.out.println(status);
}
2.导入mysql数据库数据
public void importData() throws IOException {
//1.查询所有数据,mysql
List<Goods> goodsList = goodsMapper.findAll();
//System.out.println(goodsList.size());
//2.bulk导入
BulkRequest bulkRequest = new BulkRequest();
//2.1 循环goodsList,创建IndexRequest添加数据
for (Goods goods : goodsList) {
//2.2 设置spec规格信息 Map的数据 specStr:{}
//goods.setSpec(JSON.parseObject(goods.getSpecStr(),Map.class));
String specStr = goods.getSpecStr();
//将json格式字符串转为Map集合
Map map = JSON.parseObject(specStr, Map.class);
//设置spec map
goods.setSpec(map);
//将goods对象转换为json字符串
String data = JSON.toJSONString(goods);//map --> {}
//创建文档对象
IndexRequest indexRequest = new IndexRequest("goods");
//设置文档对象参数,id=数据库中的唯一id
indexRequest.id(goods.getId()+"").source(data, XContentType.JSON);
bulkRequest.add(indexRequest);
}
//统一添加好后再一起提交
BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(response.status());
}
3.yml配置
对mysql数据库的支持
elasticsearch:
host: 192.168.93.133
port: 9200
# datasource
spring:
datasource:
url: jdbc:mysql://192.168.93.133:3307/shopping?serverTimezone=UTC # 由于是使用的虚拟机所以只能这样写
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml # mapper映射文件路径
type-aliases-package: com.itheima.elasticsearchdemo2.domain # 设置resulttyoe的别名
高级查询(API)❤️
查询结果集概述
须知:
spring-web的依赖中集成过 jackson依赖
ES强行分页 避免数据量太大 使用searchAll 内存溢出
# 使用 GET person/_search 指令可以查询所有
{
"took" : 23, # 查询耗时
"timed_out" : false, # 是否超时
"_shards" : { # 片段
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : { # 命中数据条数
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0, # 计算分数 热度高的 显示在前面
"hits" : [ # 查询出的对象
{
"_index" : "person",
"_type" : "_doc",
"_id" : "1", # id 唯一索引
"_score" : 1.0,
"_source" : { # document的数据
"name" : "wz",
"age" : 32,
"address" : "cq"
}
}
}
]
}
}
1.matchAll查询
作用: 对指定的索引查询所有文档
分页原理: 如果查询的是第五页,20条, 会把前五页的数据都查询出来缓存到内存,但是只显示第五页的二十条数据返回显示。所以查询越多性能越慢
默认情况分页显示前10条
from 起始
size 页显示个数
GET /test2/_search
{
"query": {
"match_all": {}
},
"from": 0, //分页起始位置
"size": 20 //分页大小
}
编码
所有的有关查询的信息 都是封装到源构建器中
public void testMatchAll() throws IOException {
// 创建查询请求对象,指定查询的索引名称
SearchRequest searchRequest = new SearchRequest("goods");
// 创建源构建器SearchSourceBuilder
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 用QueryBuilders来设置查询方式、如果该查询方式有查询条件则可以使用该对象设置查询条件
QueryBuilder query = QueryBuilders.matchAllQuery();
//封装进源构建器
sourceBuilder.query(query);
// 添加源构建器 SearchSourceBuilder
//封装进查询请求
searchRequest.source(sourceBuilder);
// 指定源构建器的分页信息
sourceBuilder.from(0);
sourceBuilder.size(100);
// 正式开始查询,获取查询结果
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
//===================================================================================
//==========================以下是对返回结果集的后续处理===============================
//===================================================================================
// 获取命中对象 SearchHits
SearchHits searchHits = searchResponse.getHits();
// 获取总记录数
long value = searchHits.getTotalHits().value;
System.out.println("总记录数:"+value);
List<Goods> goodsList = new ArrayList<>();
// 获取Hits数据 数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
//获取json字符串格式的数据
String sourceAsString = hit.getSourceAsString();
//转为java对象
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
goodsList.add(goods);
}
for (Goods goods : goodsList) {
System.out.println(goods);
}
}
2.termQuery查询
作用:Term 精确匹配 不分词 指定什么字段就查找与之相同的值返回 与字段内容完全匹配
GET _search
{
"query": {
"term": {
"name": {
"value": "张三"
}
}
}
}
//其余步骤都一致,此处是 选择查询方式 term没有可以设置的查询条件。故未设置
TermQueryBuilder query = QueryBuilders.termQuery("name","张三"); //精确查询 该索引表中的 name为张三的文档
3.matchQuery查询
作用:match 并集、交集查询
首先会对该输入的值 分词处理 再判断指定的方式是交集还是并集,最终生成结果返回
// A:1、2、3 B:1、2、5
// operator:or并集=1、2、3、5
// operator:and交集=1、2
GET _search
{
"query": {
"match": {
"name": {
"query": "张三",
"operator": "or"
}
}
}
}
//查询该索引表中 字段是name的 但是会对"华为手机"进行分词,再按照给定的 AND 并集来最终返回结果
MatchQueryBuilder query = QueryBuilders.matchQuery("name", "华为手机").operator(Operator.AND);
4.模糊查询
1).WildcardQuery通配符查询
*作用: 通配符查询 ?是单个字符,是任意字符。注意竟可能星号不要写在前面
GET _search
{
"query": {
"wildcard": {
"name": {
"value": "张?"
}
}
}
}
//表示查询name 字段后仅含一个字符的所有文档
WildcardQueryBuilder query = QueryBuilders.wildcardQuery("name", "张?");
WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "华*");
2)regexpQuery正则查询
作用:使用正则表达式的格式来筛选文档
GET _search
{
"query": {
"regexp": {
"name": "[张](.)*"
}
}
}
RegexpQueryBuilder query = QueryBuilders.regexpQuery("title", "\\w+(.)*");
RegexpQueryBuilder query = QueryBuilders.regexpQuery("name", "张(.)*");
3)prefixQuery前缀查询
作用:指定起始条件
PrefixQueryBuilder query = QueryBuilders.prefixQuery("brandName", "三");
6.rangeQuery范围查询
作用:对条件进行范围性的筛选
GET _search
{
"query": {
"range": {
"age": {
"gte": 1,
"lte": 20
}
}
}
}
//范围查询
RangeQueryBuilder query = QueryBuilders.rangeQuery("price");
//以下是对该查询方式的条件进行定义
//指定下限
query.gte(2000);
//指定上限
query.lte(3000);
//排序
sourceBulider.sort("price", SortOrder.DESC);
sourceBulider.query(query);
//封装进请求
searchRequest.source(sourceBulider);
7.多字段查询
1)QueryString表达式查询
默认是 交集查询 (OR)
作用:按照输入条件 先分词 再判断是否指定并集(AND),最后分别去对应的指定字段中查找是否存在该分词数据。再返回结果
//此方式返回的查询结果 不会包含命中数据hits
GET _search
{
"query": {
"query_string": {
"query": "name:华为 OR age:1"
}
}
}
// 正确指定feilds 会返回命中数据hits
GET _search
{
"query": {
"query_string": {
"fields": ["categoryName","title","brandName"],
"query": "华为 AND 手机"
}
}
}
//方式1
QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("name:张二 AND age:1");
//方式2,链式调用【指定分词条件 --> 指定字段 --> 指定交并集】
QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("华为手机").field("title").field("categoryName").field("brandName").defaultOperator(Operator.AND);
2)SimpleQueryString多字段条件查询
作用:对多个字段查询、对于输入的关键字不会进行分词
//只是此处变为 "simple_query_string" 其余不变
GET _search
{
"query": {
"simple_query_string" : {
"fields": ["categoryName","title","brandName"],
"query": "华为 AND 手机" // 此处的 and / or 不在生效,当作一个词来分 意思是只支持交集
}
}
}
8.布尔查询
只组合其它搜索条件,无自己的特殊条件
- 组合方式
- must:条件必须成立 执行查询,并计算评分 影响性能
- filter:条件必须成立 执行查询,不计算评分
- must_not 条件必须不成立
- should 条件可以成立
GET _search
{
"query": {
"bool": {
"must": [
{
"term": {
"name": {
"value": "张三"
}
}
}
],
"filter": {
"range": {
"age": {
"gte": 1,
"lte": 20
}
}
}
}
}
}
//示例1
TermQueryBuilder term = QueryBuilders.termQuery("name","张三");
WildcardQueryBuilder wildcard = QueryBuilders.wildcardQuery("name", "张?");
BoolQueryBuilder query = QueryBuilders.boolQuery();
query.must(term);
query.filter(wildcard);
builder.query(query);
//示例2
public void testBoolQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("goods");
SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
//1.构建boolQuery
BoolQueryBuilder query = QueryBuilders.boolQuery();
//2.构建各个查询条件
//2.1 查询品牌名称为:华为
QueryBuilder termQuery = QueryBuilders.termQuery("brandName","华为");
query.must(termQuery);
//2.2. 查询标题包含:手机
QueryBuilder matchQuery = QueryBuilders.matchQuery("title","手机");
query.filter(matchQuery);
//2.3 查询价格在:2000-3000
QueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
((RangeQueryBuilder) rangeQuery).gte(2000);
((RangeQueryBuilder) rangeQuery).lte(3000);
query.filter(rangeQuery);
//3.使用boolQuery连接
sourceBulider.query(query);
searchRequest.source(sourceBulider);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
yBuilders.boolQuery();
query.must(term);
query.filter(wildcard);
builder.query(query);
//示例2
public void testBoolQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("goods");
SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
//1.构建boolQuery
BoolQueryBuilder query = QueryBuilders.boolQuery();
//2.构建各个查询条件
//2.1 查询品牌名称为:华为
QueryBuilder termQuery = QueryBuilders.termQuery("brandName","华为");
query.must(termQuery);
//2.2. 查询标题包含:手机
QueryBuilder matchQuery = QueryBuilders.matchQuery("title","手机");
query.filter(matchQuery);
//2.3 查询价格在:2000-3000
QueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
((RangeQueryBuilder) rangeQuery).gte(2000);
((RangeQueryBuilder) rangeQuery).lte(3000);
query.filter(rangeQuery);
//3.使用boolQuery连接
sourceBulider.query(query);
searchRequest.source(sourceBulider);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);