雅典娜意外地实现了各种功能


自我介绍

这是一位新毕业生,首次在博客上发布。
我通常会编写服务器端程序。

介绍

通过抛出查询,可以有效地搜索和聚合存储在

DB中的数据。但是,不可能将所有随着服务继续运行而累积的大量日志存储在数据库中,我们将继续将它们适当地存储在压缩文件中。

当您想收集过去的日志时,像这样的文件编写很不方便,但是通过使用Amazon Athena这样的服务,您可以像处理数据库一样查询文件。

我听说此服务的格式是每次执行查询时都会读取S3上的文件,并且我认为我可以抛出一个简单的SELECT语句。
实际上,这并不是一个性能低下的服务,在许多情况下,即使是似乎需要手书和聚合的数据格式,也有可能利用功能的强大功能进行管理,因此这里有一些此类情况的示例...

情况1:JSON解析

在一个日志中,

所在的位置存储了许多以下格式的行。

1
日付時刻|json形式のデータ|その他

从这样的行数据中提取json部分的数据,进行搜索和总计时,如果您工作稳定,我将编写一个脚本,用json解码由\\" | \\"分隔的第二个字符串。您仍然可以在Athena中查询以这种格式。

为此,请通过以下方法将json数据的值作为一列读取。

  • 创建一个以\\" | \\"分隔的csv表
  • 使json部分VARCHAR类型,json解码并检索特定密钥

如果

json部分的列名称为json_str,则在创建表后将引发的查询大致如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
WITH tmp_table_name AS (
  SELECT
    CAST(JSON_EXTRACT(JSON_PARSE(json_str), '$.id') AS INTEGER) AS id,
    CAST(JSON_EXTRACT(JSON_PARSE(json_str), '$.str') AS VARCHAR) AS str
  FROM
    table_name
)
SELECT
  *
FROM
  tmp_table_name
WHERE
  id = 125

JSON_PARSE解析以获得json类型值后,JSON_EXTRACT用jq之类的符号检索内部值。
将检索到的值转换为您喜欢的类型,准备一个带别名的表,并将其当作具有名称的表并在后续查询中键入。

您可以在不使用

WITH子句的情况下执行相同的操作,但是每次需要列信息时都必须编写CAST(...),并且不能将GROUP_BY等用于另一个名称,因此很简单。最好用WITH咬一次表转换。

补遗1

似乎相同的功能可以在MySQL 5.7或更高版本中使用。我不知道....

补遗2

我发现了许多示例,当整个

数据为json格式时,您可以使用STRUCT类型获取嵌套数据,但像此示例一样,json为csv。如果包含,则无法识别为STRUCT类型。
(当我将其定义为STRUCT<col1:str,col2:int,...>时,整个json字符串进入col1,其他列变为NULL)

情况2:用逗号分隔的列行扩展

所在的位置有一个用逗号分隔的多个值的日志,如下所示。

1
{..., "ids": "1,2,5"}

从此类行数据中提取逗号分隔的部分并进行搜索和总计时,如果您工作稳定,则可以编写一个脚本以json解码并拆分id的内容,但是即使采用这种格式,您也可以向Athena查询扔。

可以通过编写以下查询将其扩展为行数据。

1
2
3
4
5
6
7
SELECT
  *
FROM
  table_name
CROSS JOIN UNNEST (
  SPLIT(ids, ',')
) AS tmp_table_name (id)

有一个称为SPLIT的确定函数,用于通过

分隔符进行拆分。返回值是一个数组。
通过将拆分数组与CROSS JOIN UNNEST连接,您将获得n行的结果,其中拆分数组的值将被绑定到原始行。

说到

CROSS JOIN,有一幅记录数量激增的图像,但是在此查询中,UNNEST的作用是合并与长度为n的数组相对应的每一行。

情况3:逗号分隔的多列行扩展

与案例2相似,但是有一个日志,其中多个相同长度的数组之间用逗号隔开,如下所示。

1
{..., "item_ids": "1,2,5", "item_amounts": "12,25,125"}

即使在这种情况下,也可以通过将数组的连接部分设为查询,将多个数组的对应索引扩展到同一行,如下所示。

1
2
3
4
5
6
CROSS JOIN UNNEST (
  MAP(
    TRANSFORM(SPLIT(item_ids, ","), v -> CAST(v AS INTEGER)),
    TRANSFORM(SPLIT(item_amounts, ","), v -> CAST(v AS INTEGER))
  )
) AS tmp_table_name (item_id, item_amount)

结果是n行具有n个csv值的JOIN连接到原始行。

此查询中出现的MAPTRANSFORM函数是Python中的zip MAP函数。
在案例2中我没有提到它,但是SPLIT的结果是一个字符串数组,因此,如果要将其视为数字,则可以结合使用TRANSFORM函数和Lambda函数来对每个值进行转换。

摘要?印象

我很惊讶能够使用像普通编程语言这样的功能。
在文章末尾有一个指向功能列表页面的链接,但是似乎已经实现了与数字,字符串,数组等有关的基本功能。

似乎通常从事数据分析等工作的人都知道,但是如果您是一个普通的服务器人员,并且像您一样在应用程序的服务器逻辑中使用MySQL来生活,那对您也不是很了解。 。

在执行研究任务时,我可以通过轻松编写脚本来进行处理,但是如果使用这些功能,似乎仅通过引发查询即可完成的任务数量将会增加。
将来,当将诸如聚合之类的任务分配给我时,我会认为"是否可以仅通过引发查询来完成它?"

补充

本文的重点是Athena,但是实现类似功能的DB和服务应该可行,因此即使日志保存目标不是S3,也有一些服务可以执行相同的操作。是一个。

参考

Amazon Athena的Presto函数
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/functions-operators-reference-section.html

奖金

我想,"我想只用一个查询来完成聚合过程,但是不可能在大表之间抛出像JOIN这样的繁重查询吗?",但是也引发了这么繁琐的查询。我简短地听说过是这项服务的优势,所以我尝试了。
→尝试在雅典娜中联接具有1亿条记录的表