当前位置: 首页 > news >正文

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.引入esRestHighLevelClient依赖:

<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 风格的搜索引擎和分析引擎&#xff0c;具有强大的全文搜索、数据分析、机器学习等功能&#xff0c;广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引&#xff08;Index&#xff09;&#xf…...

Leetocde516. 最长回文子序列 动态规划

原题链接&#xff1a;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&#xff1a;进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...

高级生化大纲

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

YARN WebUI 服务

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

【Unity3D】利用IJob、Burst优化处理切割物体

参考文章&#xff1a; 【Unity】切割网格 【Unity3D】ECS入门学习&#xff08;一&#xff09;导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习&#xff08;十二&#xff09;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风格 …...

基于文件系统分布式锁原理

分布式锁&#xff1a;在一个公共的存储服务上打上一个标记&#xff0c;如Redis的setnx命令&#xff0c;是先到先得方式获得锁&#xff0c;ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...

简历整理YH

一&#xff0c;订单中心 1&#xff0c;调拨单 融通(Rocketmq)-订单中心&#xff1a;ECC_BMS123(已出单)&#xff0c;125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2&#xff0c;销售单 sap&#xff08;FTP&#xff09;-订单中心&#xff0c;下发1002,1003,…...

Kotlin 协程基础三 —— 结构化并发(二)

Kotlin 协程基础系列&#xff1a; Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发&#xff08;一&#xff09; Kotlin 协程基础三 —— 结构化并发&#xff08;二&#xff09; Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...

微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果

有一个需求需要在微信小程序上实现一个长按时进行语音录制&#xff0c;录制时间最大为60秒&#xff0c;录制完成后&#xff0c;可点击播放&#xff0c;播放时再次点击停止播放&#xff0c;可以反复录制&#xff0c;新录制的语音把之前的语音覆盖掉&#xff0c;也可以主动长按删…...

校园跑腿小程序---轮播图,导航栏开发

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…...

详细全面讲解C++中重载、隐藏、覆盖的区别

文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏&#xff08;Function Hiding&#xff09;概念示例代码特点 3. 函数覆盖&#xff08;重写&#xff…...

一文读懂单片机的串口

目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以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 中&#xff0c;rpx 和 upx 是两种不同的单位&#xff0c;它们的主要区别在于适用的场景和计算方式。 ### rpx&#xff08;Responsive Pixel&#xff09; - **适用场景**&#xff1a;rpx 是一种响应式单位&#xff0c;主要用于小程序和移动端的布局。 - **计算方式**…...

什么是卷积网络中的平移不变性?平移shft在数据增强中的意义

今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强&#xff08;data augmentation&#xff09;过程中&#xff0c;通过对输入图像或目标进行位置偏移&#xff08;平移&#xff09;&#xff0c;让目标在图像中呈现出…...

java.net.SocketException: Connection reset 异常原因分析和解决方法

导致此异常的原因&#xff0c;总结下来有三种情况&#xff1a; 一、服务器端偶尔出现了异常&#xff0c;导致连接关闭 解决方法&#xff1a; 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法&#xff1a; 服务器端和客户端使用相同的连接方式&#xff…...

Maven 仓库的分类

Maven 是一个广泛使用的项目构建和依赖管理工具&#xff0c;在 Java 开发生态中占据重要地位。作为 Maven 的核心概念之一&#xff0c;仓库&#xff08;Repository&#xff09;扮演着至关重要的角色&#xff0c;用于存储项目的依赖、插件以及构建所需的各种资源。 了解 Maven 仓…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

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

【WiFi帧结构】

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

ESP32读取DHT11温湿度数据

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

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

EtherNet/IP转DeviceNet协议网关详解

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

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

密码学基础——SM4算法

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