文章二十二:ElasticSearch EQL事件查询语言

EQL简介和数据准备

EQL(Event Query Language) 是 Elasticsearch 专为事件型时序数据 (日志、指标、追踪数据)设计的查询语言,主打安全威胁狩猎场景,也可用于通用事件分析。

因为在使用eql进行查询时,数据最好支持Elastic Common Schema (ECS)风格,所以使用官网的数据为大家进行演示,数据的导入方式参照官网:Example: Detect threats with EQL | Elasticsearch Guide 8.17 | Elastic

或者是大家在查看eql的文章时,可以看到他的实例数据的位置

EQL的基本使用

最基本的使用:

复制代码
//规定了事件类型的查询
//es推荐中,eql的查询数据最好是符合ECS规范,event.category是规范中的字段,他就是事件类型
GET eql_test/_eql/search
{
  "query":"""
  process where process.pid == 2012
  """
}

//最基本的查询
GET eql_test/_eql/search
{
  "query":"""
  any where process.pid == 2012
  """
}

针对下面的例子,为大家带来和es的DSL的同义查询语句:

复制代码
GET eql_test/_eql/search
{
  "query":"""
  process where process.pid == 2012
  """
}


#结合上面的解释,DSL语句可以写为

GET eql_test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "event.category": "process"
          }
        },
        {
          "term": {
            "process.pid": {
              "value": "2012"
            }
          }
        }
      ]
    }
  }
}

使用any 进行查询时相当于的DSL是:

复制代码
//最基本的查询
GET eql_test/_eql/search
{
  "query":"""
  any where process.pid == 2012
  """
}

GET eql_test/_search
{
  "query":{
    "bool": {
      "must": [
        {
          "term": {
            "process.pid": {
              "value": "2012"
            }
          }
        }
      ]
    }
  }
}

自定义事件(查询条件字段):

在上面的内容中我们可以发现,在ecs的规范下,直接使用event.category作为事件的类型进行查询,但是在实际开发中我们可能在处理历史数据或者是在数据的字段设置上没有使用ecs的规则,这里我们可以使用参数event_category_field进行指定哪个字段作为检索的条件,来取代字段event.category..

具体的使用方式如下:

通过配置修改了事件的类型,使用事件type作为查询的条件

复制代码
GET eql_test/_eql/search
{
  "event_category_field":"event.type",
  "query": """
    creation where user.full_name == "bob"
    """
}

使用属性timestamp_field指定时间字段:

复制代码
GET eql_test/_eql/search
{
  "event_category_field":"event.type",
  "timestamp_field":"@timestamp",
  "query": """
    creation where user.full_name == "bob"
    """
}

使用size指定返回数据数量:

复制代码
GET eql_test/_eql/search
{
  "event_category_field":"event.type",
  "timestamp_field":"@timestamp",
  "size":100,
  "query": """
    creation where user.full_name == "bob"
    """
}

filter_path指定返回的字段:

复制代码
GET eql_test/_eql/search?filter_path=hits.total
{
  "event_category_field":"event.type",
  "timestamp_field":"@timestamp",
  "size":100,
  "query": """
    creation where user.full_name == "bob"
    """
}

fields进行字段控制:

复制代码
GET eql_test/_eql/search
{
  "event_category_field": "event.type",
  "timestamp_field": "@timestamp",
  "size": 100,
  "query": """
    creation where user.full_name == "bob"
    """,
  "fields": [
    "system.*",
    {
      "field": "@timestamp",
      "format": "epoch_millis"
    }
  ]
}

eql的高级使用:

runtime_mappin gs结合eql:

runtime_mappings是 ES 7.11+ 提供的查询时动态字段 能力:不修改索引 Mapping、不重索引,就在本次搜索里临时算出新字段,用于过滤 / 聚合 / 排序 / 返回。

注意点:使用脚本是需要使用emit()执行,不使用fields指明字段,这个字段可以用于计算和查询,但是不可以显示出来

复制代码
GET eql_test/_eql/search
{
  "runtime_mappings": {
    "logon_id_@timestamp": {
      "type": "keyword",
      "script": {
        "source": """
          if (doc['logon_id'].size() == 0) {
            return;
          }
          emit(doc['logon_id'].value + '_' + doc['@timestamp'].value.toString());
        """
      }
    }
  },
  "event_category_field": "event.type",
  "query": """
    creation where user.full_name == "bob"
    """,
  "fields": ["logon_id_@timestamp"]
}

Sequence序列查询

sequence = 按时间先后顺序发生的一连串事件。它不是查 "有没有这些事件",而是查:

事件 A 先发生 → 然后 事件 B 发生 → 然后 事件 C 发生必须严格按时间顺序!

复制代码
 GET eql_test/_eql/search
 {
   "wait_for_completion_timeout":"10ms",
   "query":"""
   sequence with maxspan = 1h
   [ process where user.full_name == "bob"]
   [ any where user.full_name == "bob"]
   """
 }

eql进行异步查询:

复制代码
 GET eql_test/_eql/search
 {
   "wait_for_completion_timeout":"10ms",
   "query":"""
   sequence with maxspan = 1h
   [ process where user.full_name == "bob"]
   [ any where user.full_name == "bob"]
   """
 }
 
 GET _eql/search/FkhjLVVPdmQyUkZPbWkwZHdoYVoxb2cdbmZWM1YwaEJSUVNSenVIeUxyazBGUTo2MDg0NjA

pipe管道:

在写eql语句的时候我们可以通过管道获取头或者是尾巴的数据

获取尾部数据的前两条

复制代码
 GET eql_test/_eql/search
 {
   "query":"""
   any where event.category=="process" | tail 2
   """
 }

获取头部数据的前两条

复制代码
  GET eql_test/_eql/search
 {
   "query":"""
   any where event.category=="process" | head 2
   """
 }
相关推荐
jiayong233 小时前
海量数据处理技术方案与实现原理
大数据·c#·linq
千纸鹤の脉搏3 小时前
多线程的初步了解---进程与线程
java·开发语言·学习·线程
许彰午3 小时前
状态模式实战——Row对象的状态机
java·ui·状态模式
TDengine (老段)3 小时前
TDengine Commit 与 Flush 机制 — 从内存到磁盘的数据落盘全流程
大数据·数据库·物联网·架构·时序数据库·iot·tdengine
芝麻开门GEO3 小时前
2026年Q2济南企业如何选择可靠的GEO服务商
大数据·人工智能·python
搬石头的马农3 小时前
Claude Code SpringBoot开发:从0到1搭建企业级项目的6个核心Skill
java·人工智能·spring boot·后端·ai编程
西安邮电大学3 小时前
Redis为什么快?
java·redis·后端·其他·面试
折哥的程序人生 · 物流技术专研3 小时前
《Java 100 天进阶之路》第39篇:Java泛型方法的定义和使用
java·开发语言·后端·面试·求职招聘
KaMeidebaby3 小时前
卡梅德生物技术快报|Pull Down 实验在 lncRNA - 蛋白互作机制研究中的应用实例解析
大数据·前端·架构·spark·新浪微博
硅谷秋水3 小时前
世界动作模型:具身智能的下一前沿
大数据·人工智能·深度学习·计算机视觉·语言模型·机器人