web-dev-qa-db-ja.com

PrestoでJSON配列をクロス結合する方法

次のようなJSONの列を含むテーブルがあるとします。

{"payload":[{"type":"b","value":"9"}, {"type":"a","value":"8"}]}
{"payload":[{"type":"c","value":"7"}, {"type":"b","value":"3"}]}

Prestoクエリを記述して、すべてのエントリの平均b値を取得するにはどうすればよいですか?

これまでのところ、私はHiveの 側面図が爆発する のようなものを使用する必要があると思います。これはPrestoの cross join unnest に相当します。

しかし、私はcross join unnestのPrestoクエリを作成する方法に固執しています。

cross join unnestを使用してすべての配列要素を展開し、それらを選択するにはどうすればよいですか?

9
mark

これがその例です

_with example(message) as (
VALUES
(json '{"payload":[{"type":"b","value":"9"},{"type":"a","value":"8"}]}'),
(json '{"payload":[{"type":"c","value":"7"}, {"type":"b","value":"3"}]}')
)


SELECT
        n.type,
        avg(n.value)
FROM example
CROSS JOIN
    UNNEST(
            CAST(
                JSON_EXTRACT(message,'$.payload')
                    as ARRAY(ROW(type VARCHAR, value INTEGER))
                    )
                ) as x(n)
WHERE n.type = 'b'
GROUP BY n.type
_

withは、exampleという名前の共通テーブル式(CTE)を定義し、列のエイリアスはmessageです。

VALUESは逐語的なテーブル行セットを返します

UNNESTは、単一行の列内の配列を取得し、配列の要素を複数の行として返します。

CASTは、JSONタイプをARRAYに必要なUNNESTタイプに変更しています。簡単に_ARRAY<MAP<_であった可能性がありますが、列名を指定し、select句でドット表記を使用できるため、_ARRAY(ROW(_の方が優れていると思います。

_JSON_EXTRACT_はjsonPath式を使用して、payloadキーの配列値を返します

avg()および_group by_は使い慣れたSQLである必要があります。

4
Davos

ご指摘のとおり、これはついにPresto0.79で実装されました。 :)

here からのキャストの構文の例を次に示します。

select cast(cast ('[1,2,3]' as json) as array<bigint>);

特別なアドバイスですが、PrestoにはHiveのような「文字列」タイプはありません。つまり、配列に文字列が含まれている場合は、必ずタイプ 'varchar'を使用してください。そうしないと、 'タイプ配列が存在しません'というエラーメッセージが表示され、誤解を招く可能性があります。

select cast(cast ('["1","2","3"]' as json) as array<varchar>);
3
rui

問題は、古いバージョンのPrestoを実行していたことでした。

unnestはバージョン0.79で追加されました

https://github.com/facebook/presto/blob/50081273a9e8c4d7b9d851425211c71bfaf8a34e/presto-docs/src/main/sphinx/release/release-0.79.rst

1
mark