学习笔记:ElasticSearch搜索引擎

学习视频:【尚硅谷】ElasticSearch教程入门到精通(基于ELK技术栈elasticsearch 7.x+8.x新特性)
学习笔记:Elasticsearch学习笔记

目录

  • 第1章 Elasticsearch概述
    • 01. 开篇
    • 02. 技术选型
  • 2. 第二章 ElasticSearch入门
    • 03. 环境准备
    • 04. RESTful & JSON
    • 05. 倒排索引
    • 06. HTTP-索引-创建
    • 07. HTTP-索引-查询 & 删除
    • 08. HTTP-文档-创建(Put & Post)
    • 09. HTTP-文档-主键查询 & 全查询
    • 10. HTTP-文档-全量修改 & 局部修改 & 删除
    • 11. HTTP-文档-条件查询 & 字段查询 & 分页查询 & 查询排序
    • 12. HTTP-文档-多条件查询 & 范围查询
    • 13. HTTP-文档-全文检索 & 完全匹配 & 高亮查询
    • 14. HTTP-文档-聚合查询
    • 15. HTTP-映射-创建 & 查询 & 使用
    • 16. JavaAPI-环境准备
  • 3. 第三章 SpringData集成
  • 4. 第四章 SparkStreaming集成ES
  • 5. 第五章 Flink集成ES


第1章 Elasticsearch概述

01. 开篇

Elastic表示可伸缩、灵活的意思。互联网中查询的信息主要包括文章、视频、图片、网站信息等等,按数据格式分为以下三大类:

  • 结构化数据:按特定结构和组织管理数据,一般表现为二维表结构(比如用户数据,包括用户姓名、年龄、身份证号)。可以保存到关系型数据库(MySQL、Oracle),优点是方便管理和查询,缺点是扩展难
    在这里插入图片描述
  • 非结构化数据:无法用二维表结构表现的数据(如服务器日志、通信记录、文档、报表、视频、图片等)。维度广数据量大,数据存储查询成本大,需要专业人员和大量统计模型进行处理,一般会将这类数据存储于NoSQL数据库中(MongoDB、Redis、Hbase),一般按KV结构进行保存
    在这里插入图片描述
  • 半结构化数据:将数据内容和结构混合在一起,没有明显区分(如XML、HTML等)。一般保存在NoSQL数据库中(MongoDB、Redis、Hbase),缺点是查询其中内容并不容易
    在这里插入图片描述

准确快速地查询结构化数据和非结构化数据当中的内容,是非常重要的。实时数据的采集、分析、存储是未来计算机处理技术发展的方向,ES在这些方面表现良好

02. 技术选型

Elasticsearch 是什么
The Elastic Stack, 包括 Elasticsearch、 Kibana、 Beats 和 Logstash(也称为 ELK Stack)。能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。

Elaticsearch,简称为 ES, ES 是一个开源的高扩展的分布式全文搜索引擎, 是整个 ElasticStack 技术栈的核心。

它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。

elastic
英 [ɪˈlæstɪk] 美 [ɪˈlæstɪk]
n. 橡皮圈(或带);松紧带
adj. 橡皮圈(或带)的;有弹性的;有弹力的;灵活的;可改变的;可伸缩的

全文搜索引擎
Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。

一般传统数据库,全文检索都实现的很鸡肋,因为一般没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对 SQL 的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。

基于以上原因可以分析得出,在一些生产环境中,使用常规的搜索方式,性能是非常差的:

  • 搜索的数据对象是大量的非结构化的文本数据。
  • 文件记录量达到数十万或数百万个甚至更多。
  • 支持大量基于交互式文本的查询。
  • 需求非常灵活的全文搜索查询。
  • 对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
  • 对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。为了解决结构化数据搜索和非结构化数据搜索性能问题,我们就需要专业,健壮,强大的全文搜索引擎 。

这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

Elasticsearch 应用案例

  • GitHub: 2013 年初,抛弃了 Solr,采取 Elasticsearch 来做 PB 级的搜索。 “GitHub 使用Elasticsearch 搜索 20TB 的数据,包括 13 亿文件和 1300 亿行代码”。
  • 维基百科:启动以 Elasticsearch 为基础的核心搜索架构
  • 百度:目前广泛使用 Elasticsearch 作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部 20 多个业务线(包括云分析、网盟、预测、文库、直达号、钱包、 风控等),单集群最大 100 台机器, 200 个 ES 节点,每天导入 30TB+数据。
  • 新浪:使用 Elasticsearch 分析处理 32 亿条实时日志。
  • 阿里:使用 Elasticsearch 构建日志采集和分析体系。
  • Stack Overflow:解决 Bug 问题的网站,全英文,编程人员交流的网站。

2. 第二章 ElasticSearch入门

03. 环境准备

  • 官方网址:https://www.elastic.co/cn/
  • 官方文档: https://www.elastic.co/guide/index.html
  • 下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-8-0

解压后的 Elasticsearch 的目录结构如下 :

目录含义
bin可执行脚本目录
config配置目录
jdk内置 JDK 目录
lib类库
logs日志目录
modules模块目录
plugins插件目录

解压后,进入 bin 文件目录,启动 ES 服务 。

注意: 9300 端口为 Elasticsearch 集群间组件的通信端口, 9200 端口为浏览器访问的 http协议 RESTful 端口。

打开浏览器,输入地址:http://localhost:9200,测试返回结果,返回结果如下:

{
  "name" : "DESKTOP-LNJQ0VF",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "nCZqBhfdT1-pw8Yas4QU9w",
  "version" : {
    "number" : "7.8.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
    "build_date" : "2020-06-14T19:35:50.234439Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

04. RESTful & JSON

特定互联网软件架构原则——REST原则,REST表示资源状态转换,请求资源存在状态,该状态根据原则进行转换,符合此原则的就是RESTful

REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。 Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。

在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI (Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、 PUT、 POST 和DELETE。

在 REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目
标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、 POST、PUT、 DELETE,还可能包括 HEAD 和 OPTIONS。简单的理解就是,如果想要访问互联网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径, 以及对资源进行的操作(增删改查)

REST 样式的 Web 服务若有返回结果,大多数以JSON字符串形式返回。

05. 倒排索引

正排索引(传统)

idcontent
1001my name is zhang san
1002my name is li si

倒排索引

keywordid
name1001, 1002
zhang1001

Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。 为了方便大家理解,我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比:
在这里插入图片描述

ES 里的 Index 可以看做一个库,而 Types 相当于表, Documents 则相当于表的行。这里 Types 的概念已经被逐渐弱化, Elasticsearch 6.X 中,一个 index 下已经只能包含一个type, Elasticsearch 7.X 中, Type 的概念已经被删除了。

06. HTTP-索引-创建

对比关系型数据库,创建索引就等同于创建数据库。

在 Postman 中,向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/shopping
请求后,服务器返回响应:

{
    "acknowledged": true, // 响应结果
    "shards_acknowledged": true, // 分片结果
    "index": "shopping" // 索引名称
}

后台日志:

[2021-04-08T13:57:06,954][INFO ][o.e.c.m.MetadataCreateIndexService] [DESKTOP-LNJQ0VF] [shopping] creating index, cause [api], templates [], shards [1]/[1], mappings []

如果重复发 PUT 请求 : http://127.0.0.1:9200/shopping 添加索引,会返回错误信息 :

{
    "error": {
        "root_cause": [
            {
                "type": "resource_already_exists_exception",
                "reason": "index [shopping/J0WlEhh4R7aDrfIc3AkwWQ] already exists",
                "index_uuid": "J0WlEhh4R7aDrfIc3AkwWQ",
                "index": "shopping"
            }
        ],
        "type": "resource_already_exists_exception",
        "reason": "index [shopping/J0WlEhh4R7aDrfIc3AkwWQ] already exists",
        "index_uuid": "J0WlEhh4R7aDrfIc3AkwWQ",
        "index": "shopping"
    },
    "status": 400
}

07. HTTP-索引-查询 & 删除

查看所有索引
在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/_cat/indices?v

这里请求路径中的_cat 表示查看的意思, indices 表示索引,所以整体含义就是查看当前 ES服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉,服务器响应结果如下 :

health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   shopping J0WlEhh4R7aDrfIc3AkwWQ   1   1          0            0       208b           208b
表头含义
health当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
status索引打开、关闭状态
index索引名
uuid索引统一编号
pri主分片数量
rep副本数量
docs.count可用文档数量
docs.deleted文档删除状态(逻辑删除)
store.size主分片和副分片整体占空间大小
pri.store.size主分片占空间大小

查看单个索引
在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping

返回结果如下:

{
    "shopping": {//索引名
        "aliases": {},//别名
        "mappings": {},//映射
        "settings": {//设置
            "index": {//设置 - 索引
                "creation_date": "1617861426847", // 设置 - 索引 - 创建时间
                "number_of_shards": "1", // 设置 - 索引 - 主分片数量
                "number_of_replicas": "1", // 设置 - 索引 - 主分片数量
                "uuid": "J0WlEhh4R7aDrfIc3AkwWQ", // 设置 - 索引 - 主分片数量
                "version": { // 设置 - 索引 - 主分片数量
                    "created": "7080099"
                },
                "provided_name": "shopping" // 设置 - 索引 - 主分片数量
            }
        }
    }
}

删除索引
在 Postman 中,向 ES 服务器发 DELETE 请求:http://127.0.0.1:9200/shopping

返回结果如下:

{
    "acknowledged": true
}

再次查看所有索引,GET http://127.0.0.1:9200/_cat/indices?v,返回结果如下:

health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

成功删除。

08. HTTP-文档-创建(Put & Post)

假设索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式

在 Postman 中,向 ES 服务器发 POST 请求:http://127.0.0.1:9200/shopping/_doc,请求体JSON内容为:

{
    "title": "小米14",
    "category": "小米",
    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
    "price": 3999.00
}

在这里插入图片描述
注意:此处发送请求的方式必须为 POST,不能是 PUT,否则会发生错误 。(因为PUT为幂等性操作)

返回结果:

{
    "_index": "shopping", // 索引
    "_type": "_doc",      // 类型-文档
    "_id": "HlZVAZABiRKfiqMg-gkO", // 唯一标识,类似MySQL的主键,随机生成
    "_version": 1,		  // 版本
    "result": "created",  // 结果,created表示创建成功
    "_shards": {
        "total": 2,		  // 分片-总数
        "successful": 1,  // 分片-总数
        "failed": 0		  // 分片-总数
    },
    "_seq_no": 0,
    "_primary_term": 1
}

上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下, ES 服务器会随机生成一个。

如果想要自定义唯一性标识,需要在创建时指定:http://127.0.0.1:9200/shopping/_doc/1localhost:9200/shopping/_create/1,请求体JSON内容为:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",		// 唯一标识为 1
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}

注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT。

09. HTTP-文档-主键查询 & 全查询

主键查询
查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询
在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping/_doc/1

返回结果:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 15,
    "_seq_no": 17,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "title": "小米14",
        "category": "小米",
        "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
        "price": 3999.00
    }
}

查找不存在的内容,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping/_doc/9

返回结果:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1001",
    "found": false
}

全部查询

查看索引下所有数据,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping/_search

返回结果:

{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            }
        ]
    }
}

10. HTTP-文档-全量修改 & 局部修改 & 删除

全量修改

和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖。

在 Postman 中,向 ES 服务器发 POST 请求:http://127.0.0.1:9200/shopping/_doc/1
请求体JSON内容为:

{
    "title":"华为手机",
    "category":"华为",
    "images":"http://www.gulixueyuan.com/hw.jpg",
    "price":1999.00
}

返回结果:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 2,
    "result": "updated", // <-----------updated 表示数据被更新
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}

局部修改

修改数据时,也可以只修改某一条数据的局部信息。

在 Postman 中,向 ES 服务器发 POST 请求:http://127.0.0.1:9200/shopping/_update/1
请求体JSON内容为:

{
	"doc": {
		"title": "小米手机",
		"category": "小米"
	}
}

返回结果如下:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 3,
    "result": "updated",//<-----------updated 表示数据被更新
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 3,
    "_primary_term": 1
}

删除

删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。

在 Postman 中,向 ES 服务器发 DELETE 请求:http://127.0.0.1:9200/shopping/_doc/1

返回结果:

{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 23,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 25,
    "_primary_term": 1
}

11. HTTP-文档-条件查询 & 字段查询 & 分页查询 & 查询排序

条件查询(URL携带参数)

查找category为小米的文档,在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping/_search?q=category:小米

返回结果:

{
    "took": 25,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 0.36464313,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 0.36464313,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.36464313,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                }
            }
        ]
    }
}

上述为URL带参数形式查询,这很容易让心怀恶意者钻空子,或者参数值出现中文会出现乱码情况。为了避免这些情况,我们可用使用带JSON请求体请求进行查询。

条件查询(请求体携带参数)

接下带JSON请求体,还是查找category为小米的文档,在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query": {
		"match": {
			"category": "小米"
		}
	}
}

返回结果与之前一致

查询全部(请求体方式)

查找所有文档内容,也可以这样,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query":{
		"match_all":{}
	}
}

返回结果:

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                }
            }
        ]
    }
}

查询指定字段

如果你想查询指定字段,在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query":{
		"match_all":{}
	},
	"_source":["title"]
}

返回结果如下:

{
    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0,
                "_source": {
                    "title": "小米14"
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "小米13"
                }
            }
        ]
    }
}

分页查询

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query": {
		"match_all": {}
	},
    "from": 0, // 页码数-1
    "size": 1  // 显示多少条
}

返回结果:

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            }
        ]
    }
}

查询排序

如果你想通过排序查出价格最高的手机,在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query": {
		"match_all": {}
	},
	"sort": {
		"price": {
			"order": "desc"
		}
	}
}

返回结果:

{
    "took": 9,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": null,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": null,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                },
                "sort": [
                    3999.0
                ]
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": null,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                },
                "sort": [
                    3599.0
                ]
            }
        ]
    }
}

12. HTTP-文档-多条件查询 & 范围查询

多条件查询——MUST

假设想找出小米牌子,价格为3999元的。

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:(must相当于MySQL的AND)

{
	"query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "category": "小米"
                    }
                },
                {
                    "match": {
                        "price": 3999
                    }
                }
            ]
        }
	}
}

返回结果:

{
    "took": 13,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.3646431,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.3646431,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            }
        ]
    }
}

多条件查询——SHOULD

假设想找出小米和华为的牌子。

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:(should相当于MySQL的OR)

{
	"query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "category": "小米"
                    }
                },
                {
                    "match": {
                        "category": "华为"
                    }
                }
            ]
        }
	}
}

返回结果:

{
    "took": 9,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 4,
            "relation": "eq"
        },
        "max_score": 1.7509375,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.7509375,
                "_source": {
                    "title": "HUAWEI Pura 70",
                    "category": "华为",
                    "images": "https://res2.vmallres.com/pimages/uomcdn/CN/pms/202405/displayProduct/10086157311748/428_428_a_web628062479CFC08B72883649F8B058507.jpg",
                    "price": 5499.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0779929,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0779929,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0779929,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            }
        ]
    }
}

范围查询

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "category": "小米"
                    }
                },
                {
                    "match": {
                        "category": "华为"
                    }
                }
            ],
            "filter": {
                "range": {
                    "price": {
                        "gt": 5000
                    }
                }
            }
        }
	}
}

13. HTTP-文档-全文检索 & 完全匹配 & 高亮查询

全文检索

这功能像搜索引擎那样,如品牌输入“小华”,返回结果带回品牌有“小米”和华为的。

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,请求体附带JSON体如下:

{
	"query": {
		"match": {
			"category" : "小华"
		}
	}
}

完全匹配

如果想要完全匹配才能命中,返回品牌有“小华”的。

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,请求体附带JSON体如下:

{
	"query": {
		"match_phrase": {
			"category" : "小华"
		}
	}
}

高亮查询
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"query": {
        "bool": {
            "must": [
                {
                    "match_phrase": {
                        "category": "为"
                    }
                }
            ]
        }
	},
    "highlight": {
        "fields": {
            "category": {} // <----高亮此字段
        }
    }
}

14. HTTP-文档-聚合查询

聚合允许使用者对 ES 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值max、平均值avg等等。

分组查询

接下来按price字段进行分组:

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"aggs":{ // 聚合操作
		"price_group":{ // 名称,随意起
			"terms":{ // 分组
				"field": "price" // 分组字段
			}
		}
	}
}

返回结果:

{
    "took": 6,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 4,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "HlZVAZABiRKfiqMg-gkO",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "小米13",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1670745532.86084186.png",
                    "price": 3599.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "title": "HUAWEI Pura 70",
                    "category": "华为",
                    "images": "https://res2.vmallres.com/pimages/uomcdn/CN/pms/202405/displayProduct/10086157311748/428_428_a_web628062479CFC08B72883649F8B058507.jpg",
                    "price": 5499.00
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "小米14",
                    "category": "小米",
                    "images": "https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1698304477.56836008.png",
                    "price": 3999.00
                }
            }
        ]
    },
    "aggregations": {
        "price_group": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": 3999.0,
                    "doc_count": 2
                },
                {
                    "key": 3599.0,
                    "doc_count": 1
                },
                {
                    "key": 5499.0,
                    "doc_count": 1
                }
            ]
        }
    }
}

上面返回结果会附带原始数据的。若不想要不附带原始数据的结果,在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"aggs": { // 聚合操作
        "price_group": { // 名称,随意起
            "terms": { // 分组
                "field": "price" // 分组字段
            }
        }
	},
    "size": 0 // 排除原始数据结果
}

求平均值

对所有手机价格求平均值。

在 Postman 中,向 ES 服务器发 GET请求:http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

{
	"aggs": { // 聚合操作
        "price_avg": { // 名称,随意起
            "avg": { // 平均值
                "field": "price" // 分组字段
            }
        }
	},
    "size": 0 // 排除原始数据结果
}

返回结果:

{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 4,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    },
    "aggregations": {
        "price_avg": {
            "value": 4274.0
        }
    }
}

15. HTTP-映射-创建 & 查询 & 使用

有了索引库,等于有了数据库中的 database。

接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。

创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。

先创建一个索引:

PUT http://127.0.0.1:9200/user

创建映射

PUT http://127.0.0.1:9200/user/_mapping

{
    "properties": {
        "name": {
            "type": "text",  // 支持全文检索
            "index": true
        },
        "sex": {
            "type": "keyword", // 需要完全匹配
            "index": true
        },
        "tel": {
            "type": "keyword", // 需要完全匹配
            "index": false
        }
    }
}

查询映射

GET http://127.0.0.1:9200/user/_mapping

返回结果:

{
    "user": {
        "mappings": {
            "properties": {
                "name": {
                    "type": "text",
                    "index": true
                },
                "sex": {
                    "type": "keyword",
                    "index": true
                },
                "tel": {
                    "type": "keyword",
                    "index": false
                }
            }
        }
    }
}

此时插入数据:

PUT localhost:9200/user/_create/1

{
    "name": "ziang",
    "sex": "male",
    "tel": 13716004539
}

测试以下三条示例请求

  • 请求1:

    GET http://127.0.0.1:9200/user/_search
    {
    	"query":{
    		"match":{
    			"name":"zi"
    		}
    	}
    }
    
  • 请求2:

    GET http://127.0.0.1:9200/user/_search
    {
    	"query":{
    		"match":{
    			"sex":"ma"
    		}
    	}
    }
    
  • 请求3:

    GET http://127.0.0.1:9200/user/_search
    {
    	"query":{
    		"match":{
    			"tel":"1371600"
    		}
    	}
    }
    

请求1可以查询出数据,但请求2不可以,因为创建映射时 “sex” 的类型为 “keyword”,需要完全匹配才能查询出来。请求3查询报错,因为创建映射时 “tel” 的 “index” 为 false。

16. JavaAPI-环境准备

新建Maven工程。添加依赖:

<dependencies>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.8.0</version>
    </dependency>
    <!-- elasticsearch 的客户端 -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.8.0</version>
    </dependency>
    <!-- elasticsearch 依赖 2.x 的 log4j -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.9</version>
    </dependency>
    <!-- junit 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

ElasticSearch示例Gitee地址: https://gitee.com/dreamPointer/dreampointer.git,在demo-elasticsearch下


3. 第三章 SpringData集成

Spring Data 是一个用于简化数据库访问和增加数据访问层功能性的项目家族。它为各种数据存储(如关系型数据库、NoSQL数据库、云服务等)提供了统一的编程模型。Spring Data 的主要目标是使开发者能够更容易地构建Spring驱动的应用程序,而无需编写大量的数据访问代码。

对于关系型数据库,Spring Data JPA 是最常用的实现之一,它基于Java Persistence API (JPA) 提供了额外的功能。Spring Data可以极大的简化JPA(Elasticsearch…)的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD 外,还包括如分页、排序等一些常用的功能。

但Spring Data 的理念不仅限于JPA,它还为MongoDB、Cassandra、Redis等多种数据存储提供了支持

Spring Data官方网址:https://spring.io/projects/spring-data/

Spring Data 常用的功能模块如下:

  • Spring Data JDBC
  • Spring Data JPA
  • Spring Data LDAP
  • Spring Data MongoDB
  • Spring Data Redis
  • Spring Data R2DBC
  • Spring Data REST
  • Spring Data for Apache Cassandra
  • Spring Data for Apache Geode
  • Spring Data for Apache Solr
  • Spring Data for Pivotal GemFire
  • Spring Data Couchbase
  • Spring Data Elasticsearch
  • Spring Data Envers
  • Spring Data Neo4j
  • Spring Data JDBC Extensions
  • Spring for Apache Hadoop

SpringData 与 MyBatis 对比:
Spring Data:它不是一个单一的持久层框架,而是一个项目系列,提供了对多种数据存储的支持,包括关系型数据库(如JPA、JDBC)、NoSQL数据库(如MongoDB、Redis、Cassandra等)以及其他数据源。Spring Data 通过提供一致的编程模型和约定,简化了数据访问层的开发。
MyBatis:它是一个基于Java的持久层框架,允许开发者自定义SQL语句、存储过程和高级映射。MyBatis 避免了几乎所有的JDBC代码和手动设置参数以及获取结果集,它使用XML或注解来配置和映射原始类型、接口和Java POJO(Plain Old Java Objects)为数据库中的记录。

SpringData集成示例Gitee地址: https://gitee.com/dreamPointer/dreampointer.git,在demo-elasticsearch下

4. 第四章 SparkStreaming集成ES

Spark Streaming 是Spark core API的扩展,大数据分析引擎,支持实时数据流的处理,并且具有可扩展,高吞吐量,容错的特点。数据可以从许多来源获取,如Kafka, Flume,Kinesis或TCP sockets,并且可以使用复杂的算法进行处理,这些算法使用诸如 map,reduce,join和 window等高级函数表示。最后,处理后的数据可以推送到文件系统,数据库等。实际上,您可以将Spark的机器学习和图形处理算法应用于数据流。

一、创建Maven项目。安装 2.12.11 版本Scala SDK

二、修改 pom 文件,添加Spark相关依赖。

<dependencies>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.12</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_2.12</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.8.0</version>
    </dependency>
    <!-- elasticsearch 的客户端 -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.8.0</version>
    </dependency>
    <!-- elasticsearch 依赖 2.x 的 log4j -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
</dependencies>

三、功能实现

import org.apache.http.HttpHost
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.ReceiverInputDStream
import org.apache.spark.streaming.Seconds
import org.apache.spark.streaming.StreamingContext
import org.elasticsearch.action.index.IndexRequest
import org.elasticsearch.client.{RequestOptions, RestClient, RestHighLevelClient}
import org.elasticsearch.common.xcontent.XContentType
import java.util.Date

object SparkStreamingESTest {

    private val hostIp = "localhost"
    private val port = 9200
    private val protocol = "http"
    private val esClient = new RestHighLevelClient(RestClient.builder(new HttpHost(hostIp, port, protocol)));

    // 应用程序的主函数
    def main(args: Array[String]): Unit = {
        // 创建一个 Spark 配置对象,设置运行模式和应用程序名称
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreamingESTest")
        // 使用 Spark 配置对象和批处理间隔(3秒)创建一个 StreamingContext 对象
        val streamContext = new StreamingContext(sparkConf, Seconds(3))
        // 根据指定主机端口创建 ReceiverInputDStream 对象,用于接收 socket 流数据
        val stream: ReceiverInputDStream[String] = streamContext.socketTextStream("localhost", 9999)

        // 遍历每个 RDD(即每个批处理的数据)
        stream.foreachRDD(
            rdd => {
                println("================" + new Date() + "================") // 每3秒循环一次

                // 遍历 RDD 中的每个元素(即每条接收到的数据)
                rdd.foreach(
                    data => {
                        // 根据空格分割数据,并设置索引名称和文档的唯一标识
                        val ss = data.split(" ")

                        println("ss = " + ss.mkString(","))

                        // 构造一个包含数据的JSON字符串
                        val productJson =
                            s"""
                               | { "data":"${ss(1)}" }
                               |""".stripMargin;

                        // 创建 IndexRequest 对象
                        val request = new IndexRequest()
                            .index("sparkstreaming")
                            .id(ss(0))
                            .source(productJson, XContentType.JSON) // 添加文档数据,数据格式为 JSON

                        // 向 ES 发送请求,获取响应对象
                        val response = esClient.index(request, RequestOptions.DEFAULT);

                        // 打印响应结果
                        System.out.println("_index:" + response.getIndex());
                        System.out.println("_id:" + response.getId());
                        System.out.println("_result:" + response.getResult());
                    }
                )
            }
        )

        // 添加 JVM 关闭钩子,停止时关闭 ES 客户端
        Runtime.getRuntime.addShutdownHook(new Thread() {
            override def run(): Unit = {
                closeClient(esClient)
            }
        })

        streamContext.start()
        streamContext.awaitTermination()
    }

    // 关闭 ES 客户端
    private def closeClient(client: RestHighLevelClient): Unit = {
        try {
            if (client != null) {
                client.close()
            }
        } catch {
            case e: Exception =>
                e.printStackTrace()
        }
    }
}

四、测试

  1. 输入 nc -l 9999 命令连接 9999 端口(nc也称为netcat,是一个功能强大的网络工具,用于在TCP或UDP协议上读取和写入数据)
  2. 输入“1100 ziang-test”,回车发送数据
  3. curl http://localhost:9200/sparkstreaming/_doc/1100,查询ES是否存在该数据

5. 第五章 Flink集成ES

Apache Spark是一-种基于内存的快速、通用、可扩展的大数据分析计算引擎。Apache Spark掀开了内存计算的先河,以内存作为赌注,贏得了内存计算的飞速发展。但是在其火热的同时,开发人员发现,在Spark中,计算框架普遍存在的缺点和不足依然没有完全解决,而这些问题随着5G时代的来临以及决策者对实时数据分析结果的迫切需要而凸显的更加明显:

  • 乱序数据,迟到数据
  • 低延迟,高吞吐,准确性
  • 容错性
  • 数据精准一次性处理(Exactly-Once)

Apache Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。在Spark火热的同时,也默默地发展自己,并尝试着解决其他计算框架的问题。慢慢地,随着这些问题的解决,Flink 慢慢被绝大数程序员所熟知并进行大力推广,阿里公司在2015年改进Flink,并创建了内部分支Blink,目前服务于阿里集团内部搜索、推荐、广告和蚂蚁等大量核心实时业务。

一、创建Maven项目。

二、修改 pom 文件,增加相关依赖类库。

<dependencies>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-scala_2.12</artifactId>
        <version>1.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-streaming-scala_2.12</artifactId>
        <version>1.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-clients_2.12</artifactId>
        <version>1.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-connector-elasticsearch7_2.11</artifactId>
        <version>1.12.0</version>
    </dependency>
    <!-- jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.11.1</version>
    </dependency>
</dependencies>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904975.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

工业协议网关:物联网时代的智慧桥梁

在物联网技术蓬勃发展的今天&#xff0c;工业协议网关作为连接工业设备和物联网系统的关键设备&#xff0c;正在发挥着越来越重要的作用。本文将带您深入了解工业协议网关的功能、应用场景以及它在工业智能化进程中的重要作用。 什么是工业协议网关&#xff1f; 工业协议网关…

机器学习中的嵌入是什么?

一、说明 嵌入是真实世界对象的数字表示&#xff0c;机器学习&#xff08;ML&#xff09;和人工智能&#xff08;AI&#xff09;系统利用它来像人类一样理解复杂的知识领域。例如&#xff0c;计算算法了解 2 和 3 之间的差为 1&#xff0c;这表明与 2 和 100 相比&#xff0c;2…

Python | Leetcode Python题解之第517题超级洗衣机

题目&#xff1a; 题解&#xff1a; class Solution:def findMinMoves(self, machines: List[int]) -> int:tot sum(machines)n len(machines)if tot % n:return -1avg tot // nans, s 0, 0for num in machines:num - avgs numans max(ans, abs(s), num)return ans

【PTA】4-1 计算二叉树最大的宽度 【数据结构】

二叉树的最大宽度是指二叉树所有层中结点个数的最大值。例如&#xff1a;下面二叉树的宽度为4. 输入二叉树的完全前序序列建立一棵二叉树&#xff08;上机作业2&#xff1a;二叉树的建立和遍历&#xff09;&#xff0c;编写算法计算并输出二叉树的宽度。 输入格式: 二叉树数据…

开源智能文档处理系统,助力医疗数据精准管理与高效整合

问题导向&#xff1a; 当前医疗文档中信息零散、数据整合度低&#xff0c;导致人工管理难度加大&#xff0c;错误率高。思通数科的系统在此背景下提供了免费的开源工具&#xff0c;帮助医疗机构实现数据的高效、精准管理&#xff0c;支持实时数据提取和智能管理。 客户案例&am…

STM32使用串口下载程序

STM32使用串口下载程序 FluMcu软件下载地址 单片机在线编程网 STM32 MCU启动模式配置(Boot Configuration) 单片机复位后&#xff0c;SYSCLK的第4个上升沿&#xff0c;BOOT引脚上的值将锁存&#xff0c;用户可以通过设置BOOT0和BOOT1引脚的值&#xff0c;来选择复位后的启动…

新兴斗篷cloak技术,你了解吗?

随着互联网技术的飞速发展&#xff0c;网络营销领域也经历了翻天覆地的变革。 从最早的网络横幅广告到如今主流的搜索引擎和社交媒体营销&#xff0c;广告形式变得越来越多样。 其中&#xff0c;搜索引擎广告一直以其精准投放而备受青睐&#xff0c;但近年来&#xff0c;一项名…

WPF+MVVM案例实战(十四)- 封装一个自定义消息弹窗控件(下)

文章目录 1、案例效果2、弹窗空间使用1.引入用户控件2、按钮命令实现 3、总结4、源代码获取 1、案例效果 2、弹窗空间使用 1.引入用户控件 打开 Wpf_Examples 项目&#xff0c;在引用中添加用户控件库&#xff0c;在 MainWindow.xaml 界面引用控件库&#xff0c;代码如下&…

教材管理系统设计与实现

教材管理系统设计与实现 1. 系统概述 教材管理系统是一个基于PHP和SQL的Web应用程序&#xff0c;旨在为学校提供一个高效的教材管理平台。该系统可以帮助管理员录入教材信息、教师查询和申请教材、学生查询教材信息&#xff0c;提高教材管理的效率和透明度。 2. 技术栈 前端…

【时间序列分析】平稳时间序列分析——Wold分解定理和延迟算子

Wold分解定理 &#xff08;这个定理是平稳时间序列分析的理论基石。&#xff09; 对于任意一个离散平稳时间序列, 它都可以分解为两个不相关的平稳序列之和, 其中一个为确定性的 (deterministic), 另一个为随机性的(stochastic) xₜVₜξₜ&#xff0c;{V₁} 为确定性平稳序列…

基于SpringBoot的汽车配件销售管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

数图携手黄商集团,打造品类空间精细化管理体系!

数图合作伙伴又1 在这秋高气爽的时节&#xff0c;满怀激情地传递着喜人的消息&#xff1a;数图的合作伙伴队伍再次壮大。位于湖北黄冈的黄商集团&#xff0c;勇于拥抱时代发展的数字变革潮流&#xff0c;积极致力于探索精细化的品类空间管理之道&#xff0c;一步一个脚印&…

大模型日报|3 篇必读的大模型论文

大家好&#xff0c;今日必读的大模型论文来啦&#xff01; 1.SocialGPT&#xff1a;贪婪分段提示优化实现社会关系推理 社会关系推理旨在从图像中识别朋友、配偶和同事等关系类别。虽然目前的方法采用了使用标注图像数据端到端训练专用网络的模式&#xff0c;但这些方法在通用…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题&#xff0c;计算两个向量的余弦值或者正弦值可以直接使用类似的方法&#xff1a; [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

利用EasyExcel实现简易Excel导出

目标 通过注解形式完成对一个方法返回值的通用导出功能 工程搭建 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

Spring Boot框架:校园社团信息管理的现代化解决方案

3系统分析 3.1可行性分析 通过对本校园社团信息管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本校园社团信息管理系统采用SSM框架&#xff0c;JAVA作…

基于SpringBoot+Vue的前后端分离的大学自动排课系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在这个背景下&#xf…

探索无线网IP地址:定义、修改方法及实践指南

在数字化时代&#xff0c;无线网络已成为我们日常生活和工作中不可或缺的一部分。它让我们能够随时随地接入互联网&#xff0c;享受信息交流的便利。然而&#xff0c;对于无线网络背后的技术细节&#xff0c;如IP地址&#xff0c;许多用户可能并不十分了解。IP地址&#xff0c;…

Spring IoC——IoC 容器的使用

1. 应用分层 应用分层是一种软件开发设计思想&#xff0c;它将应用程序分成 N 个层次&#xff0c;这 N 个层次分别负责各自的职责&#xff0c;多个层次之间协同提供完整的功能&#xff0c;根据项目的复杂度&#xff0c;可以分成三层&#xff0c;四层或更多层&#xff0c;MVC 就…

人工智能进程;算子加速的具体计算部分;大模型GPT5:参数18万亿;大模型面临问题

目录 人工智能进程 算子加速的简单理解,举例说明 一、简单理解 二、举例说明 一、算子加速的具体计算部分 二、举例说明 三、算子加速是否仅针对GPU 大模型GPT5:参数18万亿 大模型面临问题 算力集群设计框架 人工智能进程