Law*_*nce 5 sql nested metadata google-bigquery
我是BigQuery(和sql)的新手,我正在尝试设置一个表,其中每行包含一message列(字符串)和metadata列(重复).我想使用元数据列,以便我可以查询匹配某些元数据参数的消息.
例如,我的消息字符串是:
Hi honey, I'm home!
元数据列是描述消息的任意键/值对:
{"category": "personal",
"message_type": "salutation"}
这将允许我问bigquery:
回到我这有一个所有消息category的personal(或message_type的personal,等等)
重申一下,元数据键对于插入的每个消息行可能是不同的(例如,新行可能具有元数据键favorite_color而不是category).
这是我想出的架构,以支持我想要的元数据灵活性:
[
{"name": "message", "type": "string", "mode": "required"}
{"name": "metadata", "type": "record", "mode": "repeated", "fields": [ {"name": "key",
"type": "string",
"mode": "required"},
{"name": "value",
"type": "string",
"mode": "required"}]}
]
Run Code Online (Sandbox Code Playgroud)
模式期望每个元数据条目/行包含一个名为key和列的列value.它似乎工作正常.
有趣的是,Bigquery将我的消息行表示为两行(我猜这称为"展平"?):
message | metadata_key | metadata_value
------------------------------------------------------------
Hi honey, I'm home! category personal
Hi honey, I'm home! message_type salutation
Run Code Online (Sandbox Code Playgroud)
我想出了如何查询单个元数据值,如category= personal:
SELECT * FROM [table.test]
WHERE
metadata.key="category" AND metadata.value="personal"
Run Code Online (Sandbox Code Playgroud)
我回来了一行:
message | metadata_key | metadata_value
------------------------------------------------------------
Hi honey, I'm home! category personal
Run Code Online (Sandbox Code Playgroud)
这很棒!但是,我不知道如何构建一个与多个元数据参数匹配的更复杂的查询,例如:
获取所有category包含personal和message_type的消息salutation
以下查询不返回任何内容:
SELECT * FROM [table.test]
WHERE
metadata.key="category" AND metadata.value="personal" AND
metadata.key="message_type" AND metadata.value="salutation"
Run Code Online (Sandbox Code Playgroud)
我假设这是因为bigquery将我的单个消息行分解为两行(每个嵌套元数据行一行).这显然意味着我的查询将永远无法匹配单个行,因为我试图匹配两个不同的元数据行(即我要求metadata.key同时等于两个不同的值,并且元数据.value同时等于不同的值).所以我对如何恰当地构造我的查询感到有点困惑.
理想情况下,我希望BigQuery返回单行(我开始使用的原始示例行),因为它满足我的查询的两个元数据要求.
我假设我需要GROUP BY,FLATTEN,WITHIN,unflatten等的一些组合.对于这个sql/bigquery新手来说,可能性/结构的组合有点令人生畏.任何帮助赞赏:)
尝试下面 - 只是其中一个选项
它总结了你在每一行中有多少匹配,如果所有(在这种情况下 - 2)它输出它.非常简单
SELECT *,
SUM((metadata.key="category" AND metadata.value="personal")
OR (metadata.key="message_type" AND metadata.value="salutation")
) WITHIN RECORD AS check,
FROM [table.test]
HAVING check = 2
Run Code Online (Sandbox Code Playgroud)
更清洁的版本如下
SELECT *
FROM [table.test]
OMIT RECORD IF
SUM((metadata.key="category" AND metadata.value="personal")
OR (metadata.key="message_type" AND metadata.value="salutation")
) != 2
Run Code Online (Sandbox Code Playgroud)