2016-03-29 63 views
5

我是BigQuery(和sql)的新手,我试图设置一个表,其中每行包含一个message列(字符串)和metadata列(重复)。我想使用元数据列,以便查询与特定元数据参数匹配的消息。查询BigQuery嵌套/重复字段

例如,我的消息字符串是:

Hi honey, I'm home!

和元数据列是描述消息任意键/值对:

{"category": "personal", "message_type": "salutation"}

这将让我向bigquery询问:

返回我所有消息有personal(或personalmessage_type等)

为了重申,元数据键将可能是被插入每个消息行不同的一个category(例如一个新行可能有一个元数据键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"}]} 
] 

架构期望每个元数据条目/行中含有一种名为key列,列名为value。它似乎工作正常。

有趣的是,BIGQUERY表示我的消息行作为两行(我想被称为“展平”):

message     | metadata_key | metadata_value 
------------------------------------------------------------ 
Hi honey, I'm home!  category    personal 
Hi honey, I'm home!  message_type   salutation 

我想出如何查询针对单一元数据值如category = personal

SELECT * FROM [table.test] 
WHERE 
metadata.key="category" AND metadata.value="personal" 

我得到一个排回:

message     | metadata_key | metadata_value 
------------------------------------------------------------ 
Hi honey, I'm home!  category    personal 

这太棒了!不过,我不知道如何构造一个,对多个元数据参数,如火柴更复杂的查询:

取我这有一个personalcategorysalutation

message_type这以下的所有消息查询不返回任何内容:

SELECT * FROM [table.test] 
WHERE 
metadata.key="category" AND metadata.value="personal" AND 
metadata.key="message_type" AND metadata.value="salutation" 

我想这是因为BigQuery是打破我的单排的消息成两排(每个嵌套元数据行)。这显然意味着我的查询将永远无法匹配单行,因为我试图匹配两个不同的元数据行(即,我要求metadata.key同时等于两个不同的值,而元数据.value同时等于不同的值)。所以我有点难以适应如何构建我的查询。

理想情况下,我希望BigQuery返回一个单行行(我开始的原始示例行),因为它满足了我的查询的两个元数据要求。

我假设我需要GROUP BY,FLATTEN,WITHIN,unflatten等的组合。可能性/结构的组合对于这个sql/bigquery新手来说有点令人生畏。任何帮助表示赞赏:)

回答

5

尝试以下 - 只是选项
之一,它概括你有多少个“匹配有每一行中,如果所有(在这种情况下 - 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 

这个的清洁版本将如下

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