Elasticsearch:使用 ES|QL 进行地理空间搜索

news2024/9/21 2:37:29

作者:来自 Elastic Craig Taverner

多年来,Elasticsearch 一直具有强大的地理空间搜索和分析功能,但其 API 与典型的 GIS 用户习惯的 API 截然不同。在过去的一年中,我们添加了 ES|QL 查询语言,这是一种管道查询语言,与 SQL 一样简单,甚至更简单。它特别适合 Elastic 擅长的搜索、安全性和可观察性用例。我们还在 ES|QL 中添加了对地理空间搜索和分析的支持,使其使用起来更加容易,尤其是对于来自 SQL 或 GIS 社区的用户而言。

Elasticsearch 8.12 和 8.13 为 ES|QL 提供了对地理空间类型的基本支持。8.14 中地理空间搜索功能的添加大大增强了这一功能。更重要的是,这种支持旨在与 PostGIS 等其他空间数据库使用的开放地理空间联盟 (Open Geospatial Consortium - OGC) 的简单功能访问(Simple Feature Access)标准紧密一致,让熟悉这些标准的 GIS 专家更容易使用。

在本篇博文中,我们将向你展示如何使用 ES|QL 执行地理空间搜索,以及它与 SQL 和查询 DSL 等价物的比较。我们还将向你展示如何使用 ES|QL 执行空间连接,以及如何在 Kibana Maps 中可视化结果。请注意,此处描述的所有功能均处于 “technial preview - 技术预览” 状态,我们很乐意听取你对如何改进这些功能的反馈。

搜索地理空间数据

让我们从一个示例查询开始:

FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location

这将搜索与三亚凤凰国际机场 (SYX) 周围的矩形搜索多边形相交的任何城市边界多边形。

在机场、城市和城市边界的样本数据集中,此搜索找到相交多边形并从匹配的文档中返回所需的字段:

abbrevairportregioncitycity_location
SYXSanya Phoenix Int'l天涯区SanyaPOINT(109.5036 18.2533)

这很简单!现在将其与相同查询的经典 Elasticsearch 查询 DSL 进行比较:

GET /airport_city_boundaries/_search
{
  "_source": ["abbrev", "airport", "region", "city", "city_location"],
  "query": {
    "geo_shape": {
      "city_boundary": {
        "shape": {
          "type": "polygon",
          "coordinates" : [[
            [109.4, 18.1],
            [109.6, 18.1],
            [109.6, 18.3],
            [109.4, 18.3],
            [109.4, 18.1]
          ]]
        }
      }
    }
  }
}

这两个查询的目的都相当明确,但 ES|QL 查询与 SQL 非常相似。PostGIS 中的相同查询如下所示:

SELECT abbrev, airport, region, city, city_location
FROM airport_city_boundaries
WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
);

回顾一下 ES|QL 示例。很相似,对吧?

FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location

我们发现 Elasticsearch API 的现有用户发现 ES|QL 更易于使用。我们现在预计现有 SQL 用户(尤其是 Spatial SQL 用户)会发现 ES|QL 与他们习惯使用的内容非常相似。

为什么不使用 SQL?

Elasticsearch SQL 怎么样?它已经存在了一段时间,并且具有一些地理空间功能。但是,Elasticsearch SQL 是作为原始查询 API 之上的包装器编写的,这意味着只有可以转换为原始 API 的查询才受支持。ES|QL 没有这个限制。作为一个全新的堆栈,它允许进行许多在 SQL 中无法实现的优化。我们的基准测试显示 ES|QL 通常比查询 API 更快,尤其是在聚合方面!

与 SQL 的区别

显然,从前面的示例可以看出,ES|QL 与 SQL 有些相似,但也存在一些重要的区别。例如,ES|QL 是一种管道查询语言,以 FROM 之类的源命令开始,然后用管道 | 字符将所有后续命令链接在一起。这使得很容易理解每​​个命令如何接收数据表并对该表执行某些操作,例如使用 WHERE 进行过滤、使用 EVAL 添加列或使用 STATS 执行聚合。不是从 SELECT 开始定义最终输出列,而是可以有一个或多个 KEEP 命令,最后一个命令指定最终输出结果。这种结构简化了查询的推理。

关注上例中的 WHERE 命令,我们可以看到它与 PostGIS 示例非常相似:

ES|QL

WHERE ST_INTERSECTS(
    city_boundary,
    "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
)

PostGIS

WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
)

除了字符串引号字符的差异之外,最大的区别在于我们如何将字符串强制转换为空间类型。在 PostGIS 中,我们使用 ::geometry 后缀,而在 ES|QL 中,我们使用 ::geo_shape 后缀。这是因为 ES|QL 在 Elasticsearch 中运行,并且类型转换运算符 :: 可用于将字符串转换为任何受支持的 ES|QL 类型,在本例中为 geo_shape。此外,Elasticsearch 中的 geo_shape 和 geo_point 类型暗示​​了称为 WGS84 的空间坐标系,通常使用 SRID 编号 4326 来表示。在 PostGIS 中,这需要明确说明,因此在 WKT 字符串中使用 SRID=4326; 前缀。如果删除该前缀,SRID 将设置为 0,这更像 Elasticsearch 类型 cartesian_point 和 cartesian_shape,它们不与任何特定坐标系绑定。

ES|QL 和 PostGIS 都提供类型转换函数语法:

ES|QL

WHERE ST_INTERSECTS(
    city_boundary,
    TO_GEOSHAPE("POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))")
)

PostGIS

WHERE ST_INTERSECTS(
    city_boundary,
    ST_SetSRID(
      ST_GeomFromText('POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'),
      4326
    )
)

OGC 函数

Elasticsearch 8.14 引入了以下四个 OGC 空间搜索函数:

ES|QLPostGISDescription
ST_INTERSECTSST_Intersects如果两个几何图形相交,则返回 true,否则返回 false。
ST_DISJOINTST_Disjoint如果两个几何图形不相交,则返回 true,否则返回 false。与 ST_INTERSECTS 相反。
ST_CONTAINSST_Contains如果一个几何图形包含另一个几何图形,则返回 true,否则返回 false。
ST_WITHINST_Within如果一个几何图形位于另一个几何图形内,则返回 true,否则返回 false。ST_CONTAINS 的逆运算。

这些函数的行为与 PostGIS 对应函数类似,使用方式也相同。例如,如果两个几何图形相交,ST_INTERSECTS 返回 true,否则返回 false。如果你点击上表中的文档链接,你可能会注意到所有 ES|QL 示例都在 FROM 子句后的 WHERE 子句中,而所有 PostGIS 示例都使用文字几何图形。事实上,这两个平台都支持在查询的任何部分使用这些函数。

PostGIS 文档中 ST_INTERSECTS 的第一个示例是:

SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);

ES|QL 中与此等价的版本为:

ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)

请注意,我们在 PostGIS 示例中没有指定 SRID。这是因为在 PostGIS 中使用几何类型时,所有计算都是在平面坐标系上进行的,因此如果两个几何具有相同的 SRID,则 SRID 是什么并不重要。在 Elasticsearch 中,大多数函数也是如此,但是,也存在例外,其中 geo_shape 和 geo_point 使用球面计算,我们将在下一篇关于空间距离搜索的博客中看到。

ES|QL 多功能性

所以,我们已经看到了上面在 WHERE 子句和 ROW 命令中使用空间函数的示例。它们还能在哪些地方发挥作用?一个非常有用的地方是在 EVAL 命令中。此命令允许你评估表达式并返回结果。例如,让我们确定按国家名称分组的所有机场的质心(centroids)是否在勾勒出该国轮廓的边界内:

FROM airports
| EVAL in_uk = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL in_iceland = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| EVAL within_uk = ST_WITHIN(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL within_iceland = ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| STATS centroid = ST_CENTROID_AGG(location), count=COUNT() BY in_uk, in_iceland, within_uk, within_iceland
| SORT count ASC

结果符合预期,英国机场的质心位于英国边界内,而不是冰岛边界内,反之亦然:

centroidcountin_ukin_icelandwithin_ukwithin_iceland
POINT (-21.946634463965893 64.13187285885215)1falsetruefalsetrue
POINT (-2.597342072712148 54.33551226578214)17truefalsetruefalse
POINT (0.04453958108176276 23.74658354606057)873falsefalsefalsefalse

实际上,这些函数可以在查询的任何部分使用,只要它们的签名有意义。它们都接受两个参数,要么是文字空间对象,要么是空间类型的字段,并且它们都返回布尔值。一个重要的考虑因素是几何图形的坐标参考系 (coordinate reference system - CRS) 必须匹配,否则将返回错误。这意味着你不能在同一个函数调用中混合 geo_shape 和 cartesian_shape 类型。但是,你可以混合 geo_point 和 geo_shape 类型,因为 geo_point 类型是 geo_shape 类型的特殊情况,并且两者共享相同的坐标参考系。上面定义的每个函数的文档列出了支持的类型组合。

此外,任一参数都可以是空间文字或字段,顺序任意。你甚至可以指定两个字段、两个文字、一个字段和一个文字,或者一个文字和一个字段。唯一的要求是类型兼容。例如,此查询比较同一索引中的两个字段:

FROM airport_city_boundaries
| EVAL in_city = ST_INTERSECTS(city_location, city_boundary)
| STATS count=COUNT(*) BY in_city
| SORT count ASC
| EVAL cardinality = CASE(count < 10, "very few", count < 100, "few", "many")
| KEEP cardinality, count, in_city

该查询基本上询问城市位置是否在城市边界内,这通常应该是正确的,但总是有例外:

cardinalitycountin_city
few29false
many740true

一个更有趣的问题是机场位置是否位于机场服务的城市边界内。但是,机场位置位于与包含城市边界的索引不同的索引中。这需要一种方法来有效地查询和关联这两个独立索引中的数据。

空间 joins

ES|QL 不支持 JOIN 命令,但你可以使用 ENRICH 命令实现连接的特殊情况,其行为类似于 SQL 中的 “left join - 左连接”。此命令的操作类似于 SQL 中的 “左连接”,允许你根据两个数据集之间的空间关系使用来自另一个索引的数据来丰富来自一个索引的结果。

例如,让我们通过查找包含机场位置的城市边界来丰富机场表的结果,其中包含有关机场所服务城市的其他信息,然后对结果进行一些统计:

FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| MV_EXPAND city_boundary
| EVAL boundary_wkt_length = LENGTH(TO_STRING(city_boundary))
| STATS centroid = ST_CENTROID_AGG(location), count = COUNT(city_location), min_wkt = MIN(boundary_wkt_length), max_wkt = MAX(boundary_wkt_length) BY region
| SORT count DESC
| LIMIT 5

这将返回拥有最多机场的前 5 个地区,以及所有具有匹配区域的机场的质心,以及这些区域内城市边界的 WKT 表示的长度范围:

centroidcountmin_wktmax_wktregion
POINT (-32.56093470960719 32.598117914802714)90207207null
POINT (-73.94515332765877 40.70366442203522)9438438City of New York
POINT (-83.10398317873478 42.300230911932886)9473473Detroit
POINT (-156.3020245861262 20.176383580081165)5307803Hawaii
POINT (-73.88902732171118 45.57078813901171)4837837Montréal

那么,这里到底发生了什么?所谓的 JOIN 发生在哪里?查询的关键在于 ENRICH 命令:

FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary

此命令指示 Elasticsearch 丰富从 airports 索引检索到的结果,并在原始索引的 city_location 字段和 airport_city_boundaries 索引的 city_boundary 字段之间执行intersects 连接,我们在之前的几个示例中使用过该字段。但其中一些信息在此查询中并不清晰可见。我们看到的是丰富策略 city_boundaries 的名称,缺失的信息封装在该策略定义中。

{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}

在这里我们可以看到它将执行 geo_match 查询(默认为 intersects),要匹配的字段是 city_boundary,而 enrich_fields 是我们要添加到原始文档的字段。其中一个字段,即区域,实际上被用作 STATS 命令的分组键,如果没有这个 “左连接” 功能,我们就无法做到这一点。有关丰富策略的更多信息,请参阅 enrich documentation。在阅读这些文档时,你会注意到它们描述了使用丰富索引在索引时丰富数据,方法是配置摄取管道。这对于 ES|QL 不是必需的,因为 ENRICH 命令在查询时起作用。使用必要的数据和丰富策略准备丰富索引,然后在 ES|QL 查询中使用 ENRICH 命令就足够了。

你可能还注意到最常见的区域为 null。这意味着什么?回想一下,我曾将此命令比作 SQL 中的 “左连接”,这意味着如果未找到机场的匹配城市边界,则仍会返回该机场,但 airport_city_boundaries 索引中的字段值为 null。结果发现有 89 个机场未找到匹配的城市边界,而一个机场的匹配项区域字段为 null。这导致结果中有 90 个机场没有 region。另一个有趣的细节是需要 MV_EXPAND 命令。这是必要的,因为 ENRICH 命令可能会为每个输入行返回多个结果,而 MV_EXPAND 有助于将这些结果分成多行,每个结果一行。这也解释了为什么 “Hawaii” 显示不同的 min_wkt 和 max_wkt 结果:有多个区域(regions)具有相同的名称但不同的边界。

Kibana 地图

Kibana 在地图应用程序中添加了对 Spatial ES|QL 的支持。这意味着你现在可以使用 ES|QL 在 Elasticsearch 中搜索地理空间数据,并在地图上可视化结果。

添加图层菜单中有一个新的图层选项,称为 “ES|QL”。与迄今为止描述的所有地理空间功能一样,该选项处于 “technical preview - 技术预览” 状态。选择此选项可让你根据 ES|QL 查询的结果向地图添加图层。例如,你可以向地图添加一个显示世界上所有机场的图层。

或者你可以添加一个显示 airport_city_boundaries 索引中的多边形的图层,或者更好的是,上面的复杂 ENRICH 查询如何生成每个地区有多少个机场的统计数据?

接下来是什么?

你可能已经注意到,在上面的两个示例中,我们又挤进了另一个空间函数 ST_CENTROID_AGG。这是 STATS 命令中使用的聚合函数,也是我们计划添加到 ES|QL 的众多空间分析功能中的第一个。当我们有更多内容要展示时,我们会在博客中介绍它!

在此之前,我们想告诉你更多有关我们开发的一项特别令人兴奋的功能的信息:执行空间距离搜索的能力,这是 Elasticsearch 最常用的空间搜索功能之一。你能想象距离搜索的语法可能是什么样子吗?也许类似于 OGC 函数?请继续关注本系列的下一篇博客以了解详情!

剧透警告:Elasticsearch 8.15 刚刚发布,其中包括使用 ES|QL 进行空间距离搜索!

准备好自己尝试一下了吗?开始免费试用。
想要获得 Elastic 认证吗?了解下一次 Elasticsearch 工程师培训何时开始!

原文:Geospatial search with Elasticsearch ES|QL — Search Labs

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React原理之React整体渲染流程

前置知识&#xff1a;深度优先搜索(DFS)、Fiber 节点 在上一篇 React原理篇之 React 整体架构解读中&#xff0c;提到了 Fiber 架构中的几个核心概念&#xff1a; Scheduler&#xff08;调度器&#xff09;&#xff1a;根据任务的优先级安排任务执行顺序。Reconciler&#xff…

CUDA-MODE 第一课课后实战(下)

我的课程笔记&#xff0c;欢迎关注&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode CUDA-MODE 第一课课后实战&#xff08;下&#xff09; Nsight Compute Profile结果分析 继续对Nsight Compute的Profile结果进行分析&#xff0…

PyQT 串口改动每次点开时更新串口信息

class MainWindow(QWidget, Ui_Form):def __init__(self):super().__init__(parentNone)self.setupUi(self)self.comboBox.installEventFilter(self) # 加载事件过滤器self.comboBox.addItems(get_ports())def eventFilter(self, obj, event): # 定义事件过滤器if isinstance(o…

前端容器化部署:解决重启容器时的静态资源丢失问题

文章目录 什么是前端容器化&#xff1f;重启容器时静态资源丢失的问题解决静态资源丢失的方案1. 使用持久化卷创建和挂载卷使用Docker Compose定义卷 2. 使用对象存储将静态资源上传到对象存储 3. 使用构建时持久化使用CI/CD管道 4. 使用动态加载和缓存使用浏览器缓存使用服务端…

Java 8日期时间API革新:从Date到LocalDate、LocalTime与LocalDateTime的转型与优势解析

文章目录 前言一、基础介绍1.Date2.LocalDate3.LocalTime4.LocalDateTime 二、区别三、推荐场景四、推荐原因总结 前言 在Java的发展历程中&#xff0c;日期和时间的处理一直是开发者们关注的焦点。从早期的java.util.Date类到java.util.Calendar接口&#xff0c;虽然为日期时间…

Linux从0到1——进程池

Linux从0到1——进程池 1. 进程池的概念2. 进程池实现思路3. 进程池的代码实现3.1 创建管道&#xff0c;创建子进程3.2 封装任务3.3 Work接口3.4 发送任务3.5 回收资源&#xff0c;关闭管道&#xff08;重点&#xff09;3.6 改造CreatChannels接口 4. 完整代码 1. 进程池的概念…

数据结构面试-核心概念-问题理解

目录 1.数据结构及其分类 2.时间复杂度与空间复杂度及大O表示法 3.循环队列及其判断队空和队满的方法 4.栈与队列在计算机系统中的应用 5.串的模式匹配算法 6.线索二叉树、二叉搜索树、平衡二叉树 7.哈夫曼树与哈夫曼编码 8.DFS与BFS 9.最小生成树及其构建算法 10.最短…

谭晓生解读:AI如何重塑网络安全的未来?

导语 | 当前&#xff0c;对网络安全而言&#xff0c;每一次新的信息技术浪潮都蕴含着巨大机会&#xff0c;同时也意味着巨大的挑战。大模型的发展&#xff0c;是带来了更大的AI安全风险&#xff0c;还是将赋能提升网络安全呢&#xff1f;网络安全正在迎来一场重大范式转移&…

【网络编程】TCP通信基础模型实现

tcpSer.c #include <myhead.h> #define SER_IP "192.168.119.143" // 设置IP地址 #define SER_PORT 6666 // 设置端口号 int main(int argc, const char *argv[]) {// 1.创建socketint serfd socket(AF_INET, SOCK_STREAM, 0);// 参数1表示ipv4// 参数2表…

基于redis的zset实现排行榜

文章目录 &#x1f31e; Sun Frame&#xff1a;SpringBoot 的轻量级开发框架&#xff08;个人开源项目推荐&#xff09;&#x1f31f; 亮点功能&#x1f4e6; spring cloud模块概览常用工具 &#x1f517; 更多信息1.sun-club-subject集成redis1.sun-club-domain引入依赖2.sun-…

Linux 内核源码分析---内核 Netlink 套接字

linux 内核一直存在的一个严重问题就是内核态和用户态的交互的问题&#xff0c;对于这个问题内核大佬们一直在研究各种方法&#xff0c;想让内核和用户态交互能够安全高效的进行。如系统调用&#xff0c;proc&#xff0c;sysfs 等内存文件系统&#xff0c;但是这些方式一般都比…

从今年的计算机视觉比赛看风向

记第一次参加CV比赛的经历-长三角&#xff08;芜湖&#xff09;人工智能视觉算法大赛-CSDN博客 去年参赛的记录里说了&#xff1a; 最近&#xff0c;同样的由芜湖举办的比赛又上线了&#xff0c;果然&#xff1a; 2023年是这些赛题&#xff0c;典型的CV&#xff1a; 今年变成…

如何高效记录并整理编程学习笔记?一个好的笔记软件往往可以达到事半功倍的学习效果 φ(* ̄0 ̄)

在编程学习的旅程中&#xff0c;良好的笔记习惯不仅是知识积累的基石&#xff0c;更是提升学习效率、巩固学习成果的关键。选择合适的笔记工具&#xff0c;并掌握其高效使用方法&#xff0c;对于每一位编程学习者而言都至关重要。本文将从笔记工具的选择角度出发&#xff0c;探…

Linux 中断机制(一)之中断和异常

目录 一、什么是中断1、概述2、中断的分类 二、中断和异常1、中断和异常2、中断的上下部3、异常4、APIC5、中断描述符表 三、软件实现 一、什么是中断 1、概述 中断&#xff08;interrupt&#xff09;是指在 CPU 正常运行期间&#xff0c; 由外部或内部事件引起的一种机制。 …

Miracast ——随时随地在Wi-Fi®设备上分享高清内容

Miracast 是一种无线显示技术&#xff0c;由 Wi-Fi 联盟开发&#xff0c;允许设备之间通过无线方式分享多媒体内容。 Wi-Fi CERTIFIED Miracast™支持在Miracast设备之间无缝显示多媒体内容。Miracast使用户能够通过无线连接在Wi-Fi设备之间分享多媒体内容&#xff0c;包括高分…

六西格玛绿带培训对企业有什么帮助?

六西格玛&#xff0c;这一源自摩托罗拉、风靡全球的管理哲学和方法论&#xff0c;以其严谨的数据分析、持续改进的流程优化理念&#xff0c;帮助无数企业实现了从“好”到“卓越”的跨越。而六西格玛绿带&#xff0c;作为这一体系中的中坚力量&#xff0c;是连接高层管理者与一…

Linux--C语言之分支结构

文章目录 一、分支结构&#xff08;一&#xff09;概念&#xff08;二&#xff09;条件构建1.关系表达式&#xff1a;2.逻辑表达式&#xff1a;3.常量/变量&#xff1a;值是否非0&#xff0c;取值&#xff08;0|1&#xff09; &#xff08;三&#xff09;选择结构的形式1.单分支…

QT容器组

目录 容器组 Group BoX&#xff08;组&#xff09; Scroll Area&#xff08;组滑动&#xff09; Tool Box&#xff08;分页显示&#xff09; Tab Widget&#xff08;也是分页显示&#xff09; Stacked widget&#xff08;也是分页&#xff09; Frame&#xff08;就一个框…

无字母数字webshell之命令执行

文章目录 无字母数字的webshell构造技巧php7下简单解决问题php5下解决问题glob开始操作 无字母数字的webshell构造技巧 <?php if(isset($_GET[code])){$code $_GET[code];if(strlen($code)>35){die("Long.");}if(preg_match("/[A-Za-z0-9_$]/",$c…

应对FingerprintJS反爬:Selenium的破解策略与技术详解

目录 引言 FingerprintJS技术概述 技术原理 应用场景 应对策略 高级解决方案 代码实现与案例分析 去除webdriver特征 使用Undetected_chromedriver 案例分析&#xff1a;爬取目标网站数据 结论 引言 在现代互联网环境中&#xff0c;网站反爬技术日益成熟&#xff0…