Elasticsearch介绍及使用
Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎,具有强大的全文搜索、数据分析、机器学习等功能,广泛应用于日志分析、实时数据分析、全文检索等场景。
核心概念
- 索引(Index):类似于传统数据库中的数据库,是存储数据的逻辑容器。一个索引可以包含多个类型的数据,每个索引都有一个唯一的名称用于标识。
- 类型(Type):在早期版本中,一个索引可以有多个类型,用来区分不同类型的数据,但在 7.x 及以上版本中,一个索引只能有一个类型,且默认类型为“_doc”。
- 文档(Document):是 Elasticsearch 中存储和检索的基本数据单元,以 JSON 格式表示。每个文档都有一个唯一的 ID,用于在索引中定位和操作文档。
- 字段(Field):是文档中的一个属性或键值对,用于存储具体的数据内容,如姓名、年龄、价格等。字段有不同的数据类型,如文本、数字、日期等,不同的数据类型决定了字段的存储和检索方式。
主要特点
- 高性能全文搜索:基于 Lucene 的倒排索引技术,能够快速地对文本数据进行全文搜索。它会将文本数据拆分成单词或词汇,建立索引,当进行搜索时,通过查找索引快速定位到包含搜索关键词的文档,大大提高了搜索效率。
- 分布式架构:可以部署在多个节点上,形成一个分布式集群。数据会被自动分片存储在不同的节点上,当一个节点出现问题时,其他节点可以继续提供服务,保证了系统的高可用性和数据的可靠性。同时,分布式架构也使得 Elasticsearch 能够处理海量的数据和高并发的请求。
- 易于扩展:随着数据量和访问量的增加,可以通过简单地增加节点来水平扩展集群。新加入的节点会自动参与数据的存储和查询工作,无需对现有系统进行复杂的改造,能够灵活地应对业务的增长。
- RESTful API:提供了基于 HTTP 协议的 RESTful 风格的 API 接口,方便开发者使用各种编程语言进行集成和开发。通过简单的 HTTP 请求,就可以完成数据的增删改查、索引管理、查询分析等各种操作,降低了开发难度和成本。
- 多租户支持:在 Elasticsearch 集群中,可以创建多个索引,每个索引可以视为一个独立的“租户”,不同租户之间的数据相互隔离。这使得 Elasticsearch 能够在一个集群中同时为多个应用程序或用户提供服务,提高了资源利用率。
- 强大的聚合分析功能:除了基本的搜索功能,还提供了丰富的聚合分析功能,如统计、分组、排序、时间序列分析等。可以对搜索结果进行进一步的数据挖掘和分析,帮助用户快速获取数据的统计信息和趋势,为决策提供支持。
常见应用场景
- 日志分析:能够高效地收集、存储和分析各种日志数据,如服务器日志、应用程序日志、网络设备日志等。通过对日志数据的搜索、过滤、聚合分析,可以快速定位系统故障、性能瓶颈、安全问题等,为运维人员提供有力的工具。
- 实时数据分析:适用于需要实时处理和分析大量数据的场景,如金融交易监控、社交媒体数据监测、物联网设备数据处理等。Elasticsearch 可以实时地接收数据,快速地进行查询和分析,及时发现异常情况并做出响应。
- 全文检索:为各种需要全文检索功能的应用程序提供支持,如电子商务网站的商品搜索、知识管理系统的内容检索、新闻网站的新闻搜索等。能够根据用户的输入关键词,快速地在海量文本数据中找到匹配的结果,并按照相关性进行排序,提升用户体验。
- 机器学习:结合 Elasticsearch 的机器学习功能,可以对数据进行自动分析和建模,实现异常检测、预测分析等高级功能。例如,在网络安全领域,通过机器学习算法对网络流量数据进行分析,自动识别潜在的攻击行为;在电商领域,预测用户的购买行为和需求。
架构组件
- 节点(Node):是 Elasticsearch 集群中的一个服务器实例,承担着数据存储、查询处理、集群管理等任务。节点之间通过网络进行通信和协作,共同构成一个完整的 Elasticsearch 集群。
- 集群(Cluster):由一个或多个节点组成,通过配置集群名称来标识。集群负责管理节点、分配分片、处理请求等,保证数据的一致性和高可用性。集群中的主节点(Master Node)负责集群级别的操作,如创建索引、分配分片、节点发现等,数据节点(Data Node)主要负责存储数据和执行查询操作。
- 分片(Shard):为了提高数据的存储能力和查询性能,索引会被分割成多个分片,每个分片是一个独立的 Lucene 索引。分片可以分布在不同的节点上,当进行查询时,查询请求会被分发到各个分片上并行执行,然后将结果汇总返回。分片的数量在索引创建时确定,可以根据数据量和查询需求进行合理配置。
- 副本(Replica):是分片的副本,用于提高数据的可靠性和查询性能。当一个分片出现故障时,副本可以接管其查询请求,保证服务的可用性。同时,副本也可以分担查询负载,提高查询的并发处理能力。副本的数量可以根据集群的节点数量和可靠性要求进行配置。
数据写入与查询流程
- 数据写入流程:
- 客户端发送写入请求:用户或应用程序通过 Elasticsearch 的 RESTful API 向集群发送数据写入请求,请求中包含要写入的索引名称、文档数据等信息。
- 主节点路由请求:主节点接收到请求后,根据索引的分片策略,将写入请求路由到对应的主分片所在的节点。
- 主分片写入数据:主分片节点接收到请求后,将数据写入本地的分片中,并记录操作日志。写入成功后,会将操作日志发送给对应的副本分片节点。
- 副本分片同步数据:副本分片节点接收到操作日志后,会根据日志内容将数据同步到本地的副本分片中。当所有副本分片都成功同步数据后,主分片节点会向客户端返回写入成功的响应。
- 数据查询流程:
- 客户端发送查询请求:用户或应用程序通过 RESTful API 向集群发送查询请求,请求中包含查询条件、索引名称等信息。
- 主节点分发查询请求:主节点接收到查询请求后,根据索引的分片分布情况,将查询请求分发到所有相关的分片所在的节点。
- 分片节点执行查询:各个分片节点接收到查询请求后,在本地的分片中执行查询操作,根据查询条件检索匹配的文档,并将查询结果返回给主节点。
- 主节点汇总结果:主节点接收到各个分片节点返回的查询结果后,对结果进行汇总和排序等处理,然后将最终的查询结果返回给客户端。
Elasticsearch基础概念
Index:索引(index),就是文档的集合,类似数据库的表(table)
Document:文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
Field:字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
Mapping:Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema)
DSL:DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD
倒排索引
正向索引
- 文档 ID:用于唯一标识每个文档,类似数据库表中的主键,有了它就能精准定位到特定的某一文档。
- 索引项:跟在文档 ID 后面,包含了文档中的各类关键元素,比如文本里的词汇、数据记录的属性值等,有的还会附上这些元素在文档中的具体位置信息。
倒排索引
-
文档(Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息。
-
词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条。
对比
正向索引的表结构
id(索引) | title | price |
---|---|---|
1 | 小米手机 | 3499 |
2 | 华为手机 | 4999 |
3 | 华为小米充电器 | 49 |
4 | 小米手环 | 49 |
搜索流程:
-
1)如检查到搜索条件为
like '%手机%'
,需要找到title
中包含手机
的数据 -
2)逐条遍历每行数据(每个叶子节点),比如第1次拿到
id
为1的数据 -
3)判断数据中的
title
字段值是否符合条件 -
4)如果符合则放入结果集,不符合则丢弃
-
5)回到步骤1
倒排索引的表结构
词条(索引) | 文档id |
---|---|
小米 | 1,3,4 |
手机 | 1,2 |
华为 | 2,3 |
充电器 | 3 |
手环 | 4 |
搜索流程:
1)如用户输入条件"华为手机"
进行搜索。
2)对用户输入条件分词,得到词条:华为
、手机
。
3)拿着词条在倒排索引中查找(由于词条有索引,查询效率很高),即可得到包含词条的文档id:1、2、3
。
4)拿着文档id
到正向索引中查找具体文档即可(由于id
也有索引,查询效率也很高)。
正向索引:
-
优点:
-
可以给多个字段创建索引
-
根据索引字段搜索、排序速度非常快
-
-
缺点:
-
根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
-
倒排索引:
-
优点:
-
根据词条搜索、模糊搜索时,速度非常快
-
-
缺点:
-
只能给词条创建索引,而不是字段
-
无法根据字段做排序
-
安装Elasticsearch
1.使用docker安装单机版的Elasticsearch
docker run -d \--name es \-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \-e "discovery.type=single-node" \-v es-data:/usr/share/elasticsearch/data \-v es-plugins:/usr/share/elasticsearch/plugins \--privileged \--network es-net \-p 9200:9200 \-p 9300:9300 \--restart=always \elasticsearch:7.12.1
代码解读:
-d:让容器在后台运行
--name:指定创建的容器名称
-e:设置容器内的环境变量
-v:将容器内的目录挂载到外部的卷上
--privileged:以特权模式运行容器
--network:将容器连接到名为 es-net 的 Docker 网络,在我们搭建服务器的时候可以创建一个docker网络,将要互相通信的放在这一个网络里面。注意:这里需要先用docker network create创建一个docker网络这里才能指定
-p:将容器的端口映射到主机的端口
--restart=always:设置容器自启动
elasticsearch:7.12.1:要运行的 Docker 镜像名称和标签,如果我们指定这个镜像本地没有这个版本就会进行下载。注意:这里我们采用的是elasticsearch的7.12.1版本,由于8以上版本的JavaAPI变化很大,在企业中应用并不广泛,企业中应用较多的还是8以下的版本。
2.防火墙开放端口
#1.开放es端口
firewall-cmd --zone=public --add-port=9200/tcp --add-port=9300/tcp --permanent
#2.重新加载防火墙配置
firewall-cmd --reload
也可以关闭防火墙
systemctl stop firewalld
3.访问9200端口验证es是否启动成功
地址格式:主机IP:9200
IK分词器
Elasticsearch的关键就是倒排索引,而倒排索引依赖于对文档内容的分词,而分词则需要高效、精准的分词算法,IK分词器就是这样一个中文分词算法。
安装
方法一:在线安装
docker exec -it es ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
重启es容器
docker restart es
方法二:离线安装
首先,查看之前安装的es容器的plugins数据卷目录:
docker volume inspect es-plugins
结果如下:
进入/var/lib/docker/volumes/es-plugins/_data目录,将我们本地的ik上传到这个目录下
重启es容器
docker restart es
使用
IK分词器包含两种模式:
ik_smart
:智能语义切分
示例:
POST /_analyze
{"analyzer": "ik_smart","text": "我是一个程序员"
}
结果:
{"tokens" : [{"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "是","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "一个","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 2},{"token" : "程序员","start_offset" : 4,"end_offset" : 7,"type" : "CN_WORD","position" : 3}]
}
ik_max_word
:最细粒度切分
示例:
POST /_analyze
{"analyzer": "ik_max_word","text": "我是一个程序员"
}
结果:
{"tokens" : [{"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "是","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "一个","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 2},{"token" : "一","start_offset" : 2,"end_offset" : 3,"type" : "TYPE_CNUM","position" : 3},{"token" : "个","start_offset" : 3,"end_offset" : 4,"type" : "COUNT","position" : 4},{"token" : "程序员","start_offset" : 4,"end_offset" : 7,"type" : "CN_WORD","position" : 5},{"token" : "程序","start_offset" : 4,"end_offset" : 6,"type" : "CN_WORD","position" : 6},{"token" : "员","start_offset" : 6,"end_offset" : 7,"type" : "CN_CHAR","position" : 7}]
}
拓展词典
随着互联网的发展,“造词运动”也越发的频繁。出现了很多新的词语,在原有的词汇列表中并不存在,如:“逆天、依托答辩、我了个豆”
POST /_analyze
{"analyzer": "ik_max_word","text": "逆天、依托答辩、我了个豆"
}
结果:
{"tokens" : [{"token" : "逆","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "天","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "依托","start_offset" : 3,"end_offset" : 5,"type" : "CN_WORD","position" : 2},{"token" : "答辩","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 3},{"token" : "我","start_offset" : 8,"end_offset" : 9,"type" : "CN_CHAR","position" : 4},{"token" : "了","start_offset" : 9,"end_offset" : 10,"type" : "CN_CHAR","position" : 5},{"token" : "个","start_offset" : 10,"end_offset" : 11,"type" : "CN_CHAR","position" : 6},{"token" : "豆","start_offset" : 11,"end_offset" : 12,"type" : "CN_CHAR","position" : 7}]
}
可以看到,逆天和我了个豆都无法正确分词。
所以要想正确分词,IK分词器的词库也需要不断的更新,IK分词器提供了扩展词汇的功能。
1)打开IK分词器config目录:
注意:如果采用在线安装的通过,默认是没有config目录的,可以去网上找一些词库,让后创建一个config文件目录放在config目录下
2)在IKAnalyzer.cfg.xml配置文件内容添加:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 扩展配置</comment><!--可以在这里配置自己的扩展字典 --><entry key="ext_dict">ext.dic</entry>
</properties>
3)新建ext.dic文件,用记事本或者其他编辑器打开ext.dic文件,然后添加自己想要的词语即可
4)重启elasticsearch
docker restart es# 查看 日志
docker logs -f elasticsearch
5.重启之后再次执行之前的命令,可以正确分词了
{"tokens" : [{"token" : "逆天","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 0},{"token" : "依托答辩","start_offset" : 3,"end_offset" : 7,"type" : "CN_WORD","position" : 1},{"token" : "依托","start_offset" : 3,"end_offset" : 5,"type" : "CN_WORD","position" : 2},{"token" : "答辩","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 3},{"token" : "我了个豆","start_offset" : 8,"end_offset" : 12,"type" : "CN_WORD","position" : 4}]
}
还可以在IKAnalyzer.cfg.xml加上如下配置:实现更多功能
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 扩展配置</comment><!--用户可以在这里配置自己的扩展字典 --><entry key="ext_dict">ext.dic</entry><!--用户可以在这里配置自己的扩展停止词字典--><entry key="ext_stopwords">stopword.dic</entry><!--用户可以在这里配置远程扩展字典 --><!-- <entry key="remote_ext_dict">words_location</entry> --><!--用户可以在这里配置远程扩展停止词字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
RESTAPI使用
ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。
官方文档地址:
Elasticsearch Clients | Elastic
由于ES目前最新版本是8.8,提供了全新版本的客户端,老版本的客户端已经被标记为过时。而我们采用的是7.12版本,因此只能使用老版本客户端:
然后选择7.12版本,HighLevelRestClient版本:
1.引入es
的RestHighLevelClient
依赖:
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version>
</dependency>
2.初始化RestHighLevelClient:
public class IndexTest {private RestHighLevelClient client;@BeforeEachvoid setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")//es服务ip地址:端口号));}@Testvoid testConnect() {System.out.println(client);//执行不好错就行了}@AfterEachvoid tearDown() throws IOException {this.client.close();}
}
3.索引库相关操作:
public class ElasticIndexTest {private static final String MAPPING_TEMPLATE = """{"mappings": {"properties": {"id": {"type": "keyword"},"name": {"type": "text","analyzer": "ik_smart"},"price": {"type": "integer"},"image": {"type": "keyword","index": false},"category": {"type": "keyword"},"brand": {"type": "keyword"},"sold": {"type": "integer"},"commentCount": {"type": "integer","index": false},"isAD": {"type": "boolean"},"updateTime": {"type": "date"}}}}""";//JDK15新特性:三引号private RestHighLevelClient client;//创建@Testvoid testCreateIndex() throws IOException {//准备request对象CreateIndexRequest request = new CreateIndexRequest("items");//准备请求参数request.source(MAPPING_TEMPLATE, XContentType.JSON);//发送请求client.indices().create(request, RequestOptions.DEFAULT);}//判断是否存在@Testvoid testExistsndex() throws IOException {//准备request对象GetIndexRequest request = new GetIndexRequest("items");//发送请求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println("exists = " + exists);}//删除@Testvoid testDeleteIndex() throws IOException {//准备request对象DeleteIndexRequest request = new DeleteIndexRequest("items");//发送请求client.indices().delete(request, RequestOptions.DEFAULT);}@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}
4.文档相关操作:
package com.hmall.item.es;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.po.ItemDoc;
import com.hmall.item.service.IItemService;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.List;@SpringBootTest(properties = "spring.profiles.active=local")
public class ElasticDocumentTest {private RestHighLevelClient client;@Autowiredprivate IItemService itemService;@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}//创建文档@Testvoid createDoc() throws IOException {//准备文档数据//1.查询数据Item item = itemService.getById(577967L);//2.把数据库数据转成文档数据ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);//准备request对象IndexRequest request = new IndexRequest("items").id(itemDoc.getId());//构建请求参数request.source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON);//发送请求client.index(request, RequestOptions.DEFAULT);}//获取文档数据@Testvoid testGetDoc() throws IOException {//准备request对象GetRequest request = new GetRequest("items", "577967");//发送请求GetResponse response = client.get(request, RequestOptions.DEFAULT);//获取响应结果中的sourceString json = response.getSourceAsString();//转成java对象ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);System.out.println("itemDoc = " + itemDoc);}//删除文档@Testvoid testDelDoc() throws IOException {//准备request对象DeleteRequest request = new DeleteRequest("items", "577967");//发送请求client.delete(request, RequestOptions.DEFAULT);}//修改文档数据@Testvoid testUpdateDoc() throws IOException {//准备request对象UpdateRequest request = new UpdateRequest("items", "577967");request.doc("price", 29900);//发送请求client.update(request, RequestOptions.DEFAULT);}//批量操作文档:新增@Testvoid testBulkDoc() throws IOException {int pageNo = 1, pageSize = 500;while (true) {Page<Item> page = itemService.lambdaQuery().eq(Item::getStatus, 1).page(Page.of(pageNo, pageSize));List<Item> records = page.getRecords();if (records == null || records.isEmpty()) {return;}//准备BulkRequest对象BulkRequest request = new BulkRequest();for (Item item : records) {//添加批量提交的请求request.add(new IndexRequest("items").id(item.getId().toString()).source(JSONUtil.toJsonStr(BeanUtil.copyProperties(item, ItemDoc.class)), XContentType.JSON));}//提交请求client.bulk(request, RequestOptions.DEFAULT);pageNo++;}}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}
5.查询数据相关操作:
public class ElasticSearchTest {private RestHighLevelClient client;private static void parseResponseResult(SearchResponse response) {//得到命中的数据SearchHits hits = response.getHits();long total = hits.getTotalHits().value;System.out.println("total = " + total);for (SearchHit hit : hits) {//解析数据String json = hit.getSourceAsString();//封装itemDocItemDoc doc = JSONUtil.toBean(json, ItemDoc.class);//处理高亮字段Map<String, HighlightField> hfs = hit.getHighlightFields();if (hfs != null && !hfs.isEmpty()) {//更具高亮字段名获取高亮结果HighlightField hf = hfs.get("name");//用获取到的高亮值覆盖原来非高亮的字段值String hfName = hf.getFragments()[0].toString();doc.setName(hfName);}System.out.println("doc = " + doc);}}//查询全部@Testvoid testMatchAll() throws IOException {//创建SearchRequest request = new SearchRequest("items");//组织DSL查询参数request.source().query(QueryBuilders.matchAllQuery());//发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析结果parseResponseResult(response);}//根据条件查询:复合查询@Testvoid testSearch() throws IOException {//创建SearchRequest request = new SearchRequest("items");//组织DSL查询参数request.source().query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name", "脱脂牛奶")).filter(QueryBuilders.termQuery("brand", "德亚")).filter(QueryBuilders.rangeQuery("price").lt(30000)));//发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析结果parseResponseResult(response);}//分页排序@Testvoid testPageAndSort() throws IOException {int pageNo = 1, pageSize = 5;// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.搜索条件参数request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.2.排序参数request.source().sort("price", SortOrder.ASC);// 2.3.分页参数request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应parseResponseResult(response);}//根据条件获取高亮数据@Testvoid testHighlight() throws IOException {//创建SearchRequest request = new SearchRequest("items");//组织DSL查询参数//query条件request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));//高亮条件request.source().highlighter(SearchSourceBuilder.highlight().field("name"));//发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析结果parseResponseResult(response);}//数据聚合@Testvoid testAgg() throws IOException {//创建SearchRequest request = new SearchRequest("items");//组织DSL查询参数//query条件request.source().size(0);//聚合条件String brandAggName = "brandAgg";request.source().aggregation(AggregationBuilders.terms(brandAggName).field("brand").size(10));//发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析结果Aggregations aggregations = response.getAggregations();//根据聚合名称获取聚合Terms aggTerms = aggregations.get(brandAggName);//获取bucketsList<? extends Terms.Bucket> buckets = aggTerms.getBuckets();//遍历每一个bucketfor (Terms.Bucket bucket : buckets) {System.out.println("brand:"+bucket.getKeyAsString());System.out.println("count:"+bucket.getDocCount());}}@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}
相关文章:

Elasticsearch介绍及使用
Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎,具有强大的全文搜索、数据分析、机器学习等功能,广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引(Index)…...

Leetocde516. 最长回文子序列 动态规划
原题链接:Leetocde516. 最长回文子序列 class Solution { public:int longestPalindromeSubseq(string s) {int n s.size();vector<vector<int>> dp(n, vector<int>(n, 1));for (int i 0; i < n; i) {dp[i][i] 1;if (i 1 < n &&…...

iOS 逆向学习 - Inter-Process Communication:进程间通信
iOS 逆向学习 - Inter-Process Communication:进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...

高级生化大纲
一,蛋白质化学: 蛋白质分离是生物化学和分子生物学研究中的一项基本技术,用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心:通过逐…...

YARN WebUI 服务
一、WebUI 使用 与HDFS一样,YARN也提供了一个WebUI服务,可以使用YARN Web用户界面监视群集、队列、应用程序、服务、流活动和节点信息。还可以查看集群详细配置的信息,检查各种应用程序和服务的日志。 1.1 首页 浏览器输入http://node2.itc…...

【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...

【大前端】Vue3 工程化项目使用详解
目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...
基于文件系统分布式锁原理
分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是先到先得方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...
简历整理YH
一,订单中心 1,调拨单 融通(Rocketmq)-订单中心:ECC_BMS123(已出单),125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2,销售单 sap(FTP)-订单中心,下发1002,1003,…...
Kotlin 协程基础三 —— 结构化并发(二)
Kotlin 协程基础系列: Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发(一) Kotlin 协程基础三 —— 结构化并发(二) Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...
微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果
有一个需求需要在微信小程序上实现一个长按时进行语音录制,录制时间最大为60秒,录制完成后,可点击播放,播放时再次点击停止播放,可以反复录制,新录制的语音把之前的语音覆盖掉,也可以主动长按删…...

校园跑腿小程序---轮播图,导航栏开发
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...

详细全面讲解C++中重载、隐藏、覆盖的区别
文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏(Function Hiding)概念示例代码特点 3. 函数覆盖(重写ÿ…...

一文读懂单片机的串口
目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以51单片机为例 硬件连接 初始化串口 发送数据 接收数据 串口中断服务函数 代码示例 单片机串口的应用实例 单片机与…...

HTML5 网站模板
HTML5 网站模板 参考 HTML5 Website Templates...
mybatis分页插件:PageHelper、mybatis-plus-jsqlparser(解决SQL_SERVER2005连接分页查询OFFSET问题)
文章目录 引言I PageHelper坐标II mybatis-plus-jsqlparser坐标Spring Boot 添加分页插件自定义 Mapper 方法中使用分页注意事项解决SQL_SERVER2005连接分页查询OFFSET问题知识扩展MyBatis-Plus 框架结构mybatis-plus-jsqlparser的 Page 类引言 PageHelper import com.github.p…...
uniapp中rpx和upx的区别
在 UniApp 中,rpx 和 upx 是两种不同的单位,它们的主要区别在于适用的场景和计算方式。 ### rpx(Responsive Pixel) - **适用场景**:rpx 是一种响应式单位,主要用于小程序和移动端的布局。 - **计算方式**…...

什么是卷积网络中的平移不变性?平移shft在数据增强中的意义
今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强(data augmentation)过程中,通过对输入图像或目标进行位置偏移(平移),让目标在图像中呈现出…...
java.net.SocketException: Connection reset 异常原因分析和解决方法
导致此异常的原因,总结下来有三种情况: 一、服务器端偶尔出现了异常,导致连接关闭 解决方法: 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法: 服务器端和客户端使用相同的连接方式ÿ…...
Maven 仓库的分类
Maven 是一个广泛使用的项目构建和依赖管理工具,在 Java 开发生态中占据重要地位。作为 Maven 的核心概念之一,仓库(Repository)扮演着至关重要的角色,用于存储项目的依赖、插件以及构建所需的各种资源。 了解 Maven 仓…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...

密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...