Elasticsearch:ES|QL 动手实践

在我之前的文章 “Elasticsearch:ES|QL 查询语言简介”,我对 Elasticsearch 的最新查询语言 ES|QL 做了一个简单的介绍。在今天的文章中,我们详细来使用一些例子来展示 ES|QL 强大的搜索与分析功能。

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考如下的链接来进行安装:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch
  • Kibana:如何在 Linux,MacOS 及 Windows上安装 Elastic 栈中的 Kibana

在安装的时候,我们选择 Elastic Stack 8.x 来进行安装。特别值得指出的是:ES|QL 只在 Elastic Stack 8.11 及以后得版本中才有。你需要下载 Elastic Stack 8.11 及以后得版本来进行安装。

在首次启动 Elasticsearch 的时候,我们可以看到如下的输出:

我们需要记下 Elasticsearch 超级用户 elastic 的密码。

写入数据

首先,我们在 Kibana 中打入如下的命令来创建一个叫做 nyc_taxis 的索引:

PUT nyc_taxis
{
  "mappings": {
    "dynamic": "strict",
    "_source": {
      "mode": "stored"
    },
    "properties": {
      "cab_color": {
        "type": "keyword"
      },
      "dropoff_datetime": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "dropoff_location": {
        "type": "geo_point"
      },
      "ehail_fee": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "extra": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "fare_amount": {
        "type": "double"
      },
      "improvement_surcharge": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "mta_tax": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "passenger_count": {
        "type": "integer"
      },
      "payment_type": {
        "type": "keyword"
      },
      "pickup_datetime": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "pickup_location": {
        "type": "geo_point"
      },
      "rate_code_id": {
        "type": "keyword"
      },
      "store_and_fwd_flag": {
        "type": "keyword"
      },
      "surcharge": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "tip_amount": {
        "type": "double"
      },
      "tolls_amount": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "total_amount": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "trip_distance": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "trip_type": {
        "type": "keyword"
      },
      "vendor_id": {
        "type": "keyword"
      },
      "vendor_name": {
        "type": "text"
      }
    }
  }
}

接着,我们可以在地址 GitHub - liu-xiao-guo/esql 下载数据集文件 esql.json。 我们可以使用如下的命令来写入数据:

curl --cacert /Users/liuxg/elastic/elasticsearch-8.11.0/config/certs/http_ca.crt -u elastic:o6G_pvRL=8P*7on+o6XH -s -H "Content-Type: application/x-ndjson" -XPOST https://localhost:9200/nyc_taxis/_bulk --data-binary @esql.json

你需要根据自己的安装目录改写上面的证书 http_ca.crt 的路径。你需要根据 elastic 用户的密码做相应的调整。

运行完上面的命令后:

GET nyc_taxis/_count

上面的命令返回:

{
  "count": 100,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  }
}

我们可以看到 100 个数据。我们为这个数据创建一个 data view:

这样我们就为 nyc_taxis 创建好了一个 index pattern。

ES|QL 动手实践 

首先我们来做一个简单的练习。

查询数据

我们选定好时间范围,再选择 Try ES|QL

我们发现在默认的情况下,在 Query bar 里的查询语句是这样的:

from nyc_taxis | limit 10

这个相当于:

GET nyc_taxis/_search?size=10

为了方便展示,我们把编辑框放大:

这样我们的内容更容易看的清楚一些。

我们做如下的查询:

from nyc_taxis 
| limit 100
| project pickup_datetime, total_amount

在上面,我们使用 project 来返回我们想要的字段。当然我们可以使用 keep 来做同样的事情:

from nyc_taxis 
| limit 100
| keep pickup_datetime, total_amount

我们也可以在 Kibana 的 Dev Tools 中打入如下的命令:

POST /_query?format=json
{
  "query": """
    from nyc_taxis 
    | limit 100
    | keep pickup_datetime, total_amount
  """
}

我们也可以改变它的输出格式:

POST /_query?format=txt
{
  "query": """
    from nyc_taxis 
    | limit 100
    | keep pickup_datetime, total_amount
  """
}

我们可以通过 sort 来对结果进行排序:

我们可以看到结果是按照 total_amount 进行降序排列的。

在上面,我们可以看到针对 nyc_taxis 这个索引,它没有 @timestamp 时间字段。那我们该怎么办呢?我们可以通过字段 alias 来实现这个。我们执行如下的命令:

PUT nyc_taxis/_mapping
{
  "properties": {
    "@timestamp": {
      "type": "alias",
      "path": "pickup_datetime"
    }
  }
}

执行完上面的命令后,我们再次刷新页面:

可能有人想问,这个相应的 DSL 查询的语句是什么呢?如果大家对 DSL 很熟悉的话,上面的语句和下面的查询的结果是一样的:

GET nyc_taxis/_search?filter_path=**.hits
{
  "size": 100,
  "_source": false,
  "fields": [
    "pickup_datetime",
    "tolls_amount"
  ],
  "sort": [
    {
      "total_amount": {
        "order": "desc"
      }
    }
  ]
}

接下来,我们来查询 fare_amount 大于 20 的结果:

from nyc_taxis 
| where fare_amount > 20

from nyc_taxis 
| where fare_amount > 20
| where payment_type == "1"

上面显示的结果不是很清楚,我们可以使用 keep 来进行查看:

from nyc_taxis 
| where fare_amount > 20
| where payment_type == "1"
| keep fare_amount, payment_type

我们可以加入更多的过滤器:

from nyc_taxis 
| where fare_amount > 20
| where payment_type == "1"
| where tip_amount > 5
| keep fare_amount, payment_type, tip_amount

我们可以通过 limit 来限制前面的 5 个结果(在上面有6个结果显示):

在上面我有有意把 limit 写成大写的 LIMIT。我们可以看出来,它实际上是没有任何的影响。也就是说关键词和大小写无关。我们还可以针对结果进行排序:

from nyc_taxis 
| where fare_amount > 20
| where payment_type == "1"
| where tip_amount > 5
| LIMIT 5 | Sort tip_amount desc
| keep fare_amount, payment_type, tip_amount

上面的查询和下面的 DSL 查询是一样的:

GET nyc_taxis/_search
{
  "size": 5,
  "_source": [
    "fare_amount",
    "payment_type",
    "tip_amount"
  ],
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "fare_amount": {
              "gt": 20
            }
          }
        },
        {
          "term": {
            "payment_type": "1"
          }
        },
        {
          "range": {
            "tip_amount": {
              "gt": 5
            }
          }
        }
      ]
    }
  },
  "sort": [
    {
      "tip_amount": {
        "order": "desc"
      }
    }
  ]
}

很显然,我们的 ES|QL 语法更为简单明了。更重要的是,它的执行速度还更快!

接下来,我们来通过现有的字段来生成新的字段。这个也就是我们之前讲过的运行时字段(runtime fields)。我们想计算出来每英里的费用是多少:

from nyc_taxis 
| eval cost_per_mile = total_amount/trip_distance
| keep total_amount, trip_distance, cost_per_mile

如果我们使用之前的 runtime fields 来实现,也就是这样的:

GET nyc_taxis/_search?filter_path=**.hits
 {
   "_source": false, 
   "runtime_mappings": {
     "cost_per_mile": {
       "type": "double",
       "script": {
         "source": "emit(doc['total_amount'].value/doc['trip_distance'].value)"
       }
     }
   },
   "fields": [
     "total_amount",
     "trip_distance",
     "cost_per_mile"
   ]
 }

从上面的比较我们可以看出来,ES|QL 是非常简洁的,而且易于理解。

针对上面的查询,我们还可以添加过滤器来进行过滤:

from nyc_taxis 
| eval cost_per_mile = total_amount/trip_distance
| where trip_distance > 10
| keep total_amount, trip_distance, cost_per_mile

我们接下来针对生成的字段 cost_per_mile 更进一步过滤:

from nyc_taxis 
| eval cost_per_mile = total_amount/trip_distance
| where trip_distance > 10
| keep total_amount, trip_distance, cost_per_mile
| where cost_per_mile > 3.5

从显示的结果中,我们可以看出来,我们只有两个结果。

我们可更进一步进行排序:

from nyc_taxis 
| eval cost_per_mile = total_amount/trip_distance
| where trip_distance > 10
| keep total_amount, trip_distance, cost_per_mile
| where cost_per_mile > 3.5
| sort cost_per_mile desc

我们接下来针对数据进行聚合:

聚合数据

我们想知道每个 payment_type 的最多 passenger_count 的数值是多少。我们可以使用 stats 来完成:

from nyc_taxis 
| stats max_passengers=max(passenger_count) by payment_type
| keep payment_type, max_passengers

这个和如下我们以前的 DSL 相似:

GET nyc_taxis/_search?filter_path=aggregations
{
  "size": 0,
  "aggs": {
    "max_passengers": {
      "terms": {
        "field": "payment_type"
      },
      "aggs": {
        "max_count": {
          "max": {
            "field": "passenger_count"
          }
        }
      }
    }
  }
}

上面命令返回的结果是:

{
  "aggregations": {
    "max_passengers": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "1",
          "doc_count": 71,
          "max_count": {
            "value": 6
          }
        },
        {
          "key": "2",
          "doc_count": 27,
          "max_count": {
            "value": 5
          }
        },
        {
          "key": "3",
          "doc_count": 1,
          "max_count": {
            "value": 1
          }
        },
        {
          "key": "4",
          "doc_count": 1,
          "max_count": {
            "value": 1
          }
        }
      ]
    }
  }
}

很显然,我们的 ES|QL 查询会简单明了很多。

我们还可以添加其他的聚合,比如我们想得到每个 max_passengers 里支付种类 payment_type 的数量:

from nyc_taxis 
| stats max_passengers=max(passenger_count) by payment_type
| keep payment_type, max_passengers
| stats type_count=count(payment_type) by max_passengers

如上所示,在显示区了,它只显示最近的一次的聚会情况。

我们还可以针对时间来做 date_histogram 聚合:

from nyc_taxis 
| eval bucket=AUTO_BUCKET(@timestamp, 12, "2014-12-22T00:00:00.00Z", "2015-11-26T00:00:00.00Z")
| stats count(*) by bucket

这个和我们之前的如下 DSL 相似:

GET nyc_taxis/_search?filter_path=aggregations
{
  "size": 0,
  "aggs": {
    "monthly_count": {
      "date_histogram": {
        "field": "@timestamp",
        "fixed_interval": "30d"
      }
    }
  }
}

我们可以针对 payment_types 进行统计:

from nyc_taxis 
| stats payment_types = count(*) by payment_type
| sort payment_types desc

这个和 DSL 的如下统计类似:

GET nyc_taxis/_search?filter_path=aggregations
{
  "size":0,
  "aggs": {
    "payment_types": {
      "terms": {
        "field": "payment_type"
      }
    }
  }
}

在 Kibana 中进行可视化

我们也可以使用 ES|QL 在 可视化中进行使用:

我们可以自己在 Discover 中生成相应的可视化。点击上面的保存图标:

这样就很方便地生成了我们的可视化。

我们还可以对它进行编辑:

好了,今天就写到这里。希望我们都学到如何使用 ES|QL 这个工具在未来我们的工作中提供效率。

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

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

相关文章

2023亚太杯数学建模ABC题思路汇总分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

⑦【MySQL】什么是约束?如何使用约束条件?主键、自增、外键、非空....

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 约束 ⑦【MySQL】约束条件1. 约束的基本使用2.…

出行平台采集机票价格信息

在上述Python代码中,首先引入了所需的模块,然后设置了代理信息和模拟浏览器访问的网页请求头。随后,使用requests库发送代理请求,并将返回的网页内容解析为HTML。接着,从HTML中提取所需的信息,比如机票价格…

CCF ChinaSoft 2023 论坛巡礼 | 程序语义深度理解前沿进展论坛

2023年CCF中国软件大会(CCF ChinaSoft 2023)由CCF主办,CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办,将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

YOLOv8-Seg改进:小目标涨点系列篇 | TPC-YOLO-seg不同场景小目标分割均能提升 | 23年顶刊最新成果

🚀🚀🚀本文改进:轻量级的基于注意力的网络 TPC-YOLO-seg用于微小物体分割 🚀🚀🚀TPC-YOLO-seg 小目标分割首选,暴力涨点 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1)手把手教你如何…

Network(二)VLAN技术与网络层解析

一 VLAN 技术与应用 1 广播域 广播域指接收同样广播消息的范围,在该范围中的任何一个设备发送广播,所有其他设备都可以收到。默认情况下交换机的所有接口属于同一个广播域 2 VLAN概述 VLAN,Virtual LAN (虚拟局域网) 交换机的所有接口…

WebSocket Day04 : 消息推送

前言 随着Web应用程序的不断发展,实时性和交互性成为了用户体验中至关重要的一部分。传统的HTTP协议在处理实时数据传输方面存在一些局限性,而WebSocket作为一种全双工通信协议,为实现实时、高效的消息推送提供了全新的解决方案。 在Web开发…

图论15-有向图-环检测+度数+欧拉回路

文章目录 1. 有向图设计1.1 私有变量标记是否有向1.2 添加边的处理,双向变单向1.3 删除边的处理,双向变单向1.4 有向图的出度和入度 2 有向图的环检测2.1 普通的算法实现换检测2.2 拓扑排序中的环检测 3 欧拉回路 1. 有向图设计 1.1 私有变量标记是否有…

6.jvm中对象创建流程与内存分配

目录 概述对象的创建流程对象的内存分配方式对象怎样才会进入老年代大对象直接进入老年代内存担保 jvc 相关指令查看jdk默认使用的gc查看当前jdk支持的有哪些gc查看指定进程当前正在使用的gc 结束 概述 相关文章在此总结如下: 文章地址jvm基本知识地址jvm类加载系…

⑥ 【MySQL函数】字符串函数、数值函数、日期函数、流程函数

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ MySQL函数 ⑥ 字符串函数、数值函数、日期函数…

YOLOv8-Seg改进:SPPF系列改进篇 | 大核分离卷积注意力模块( Large Separable Kernel Attention)

🚀🚀🚀本文改进:大核分离卷积注意力模块( Large Separable Kernel Attention),实现涨点的目标并且降低计算复杂度和显存,引入到YOLOv8,与SPPF结合实现二次创新; 🚀🚀🚀Large Separable Kernel Attention 亲测在多个数据集能够实现涨点,同样适用于小目标分…

巅峰之作TFN AMT系列手持式信号综合测试仪

手持式信号综合测试仪是对无线电信号进行测量的必备手段,是从事电子产品研发、生产、检验的常用工具。因此,应用十分广泛,被称为工程师的射频万用表。传统的频谱分析仪的前端电路是一定带宽内可调谐的接收机,输入信号经变频器变频…

Jenkins Docker Swarm插件 配置的坑

配置 Docker Host URI 注意,这里要用 http://!!!如果按照提示里用了 tcp:// 则会报错,异常信息如下: 2023-11-13 16:28:42.6830000 [id34] WARNING o.e.j.s.h.ContextHandler$Context#log: Error while s…

探索高效智能:AI 模型的优化工具盘点 | 开源专题 No.43

openai/evals Stars: 12.3k License: NOASSERTION OpenAI Evals 是一个用于评估 LLMs (大型语言模型) 或使用 LLMs 作为组件构建的系统的框架。它还包括一个具有挑战性 evals 的开源注册表。Evals 现在支持通过 Completion Function Protocol 评估任何系统,包括 p…

Ubuntu之apt更换国内镜像源

一、需求说明 Ubuntu系统默认使用的是Ubuntu官网镜像源http://archive.ubuntu.com,网站位于境外,我们使用apt安装软件包的时候经常出现无法连接的情况,如下图所示。所以建议将系统apt安装的镜像源切换为国内镜像源。 二、更新apt镜像源步骤…

Linux常用命令——bzip2命令

在线Linux命令查询工具 bzip2 将文件压缩成bz2格式 补充说明 bzip2命令用于创建和管理(包括解压缩)“.bz2”格式的压缩包。我们遇见Linux压缩打包方法有很多种,以下讲解了Linux压缩打包方法中的Linux bzip2命令的多种范例供大家查看&…

P37[11-2]W25Q64介绍

W25Q64内部是FLASH芯片,可存储8M字节数据,掉电不丢失。 4根SPI通信线,通过STM32操作引脚电平,实现SPI通信时序,实现读取存储器芯片的目的 易失性存储器:SRAM,DRAM等(数据掉电丢失) 非易失性存储器:E2PROM,Flash等(数据掉电不丢失) 字库存储(应用在显示屏上,存储点阵…

浅谈消防设备电源监控系统在大型建筑内的应用

【摘要】:当建筑内火灾发生时,各类消防设备能否正常运行、能否发挥作用是初期火灾扑救是否成功的重要条件之一,而稳定可靠的消防设备电源则是消防设备正常工作的保障。因此针对消防设备电源的监测系统至关重要。 【关键词】:消防…

代码随想录算法训练营第五十三天丨 动态规划part14

1143.最长公共子序列 思路 本题和动态规划:718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了,但要有相对顺序,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 &quo…

https:/myproject.git did not send all necessary objects

事情是由于在git push 的时候,电脑突然蓝屏了,再打开电脑的时候,git pull git push都失效了, 粗暴的解决方式是重新在拉取代码,可以暂时解决,但是考虑到可能以后还会遇到这个问题,所以在不紧急…