私は大規模なJSONデータセット(1 GB以上)で作業しており、同様の配列オブジェクトをマージしてから、ネストされた類似オブジェクトをマージする必要があります。まず、次のような行があります。
[{"item": "item1", "attributes":[{"type": "itemtype", "colour": ["blue"]}]},
{"item": "item1", "attributes":[{"type": "itemtype", "colour": ["grey"]}]},
{"item": "item2", "attributes":[{"type": "itemtype", "colour": ["blue"]}]},
{"item": "item2", "attributes":[{"type": "itemtype2", "colour": ["orange"]}]},
{"item": "item2", "attributes":[{"type": "itemtype2", "colour": ["blue"]}]},
{"item": "item3", "attributes":[{"type": "itemtype", "colour": ["blue"]}]}]
私はjqを使ってグループ化し、コードできれいに印刷しました。
jq 'group_by(.item) | map({"item": .[0].item, "attributes": map(.attributes[])})
プロジェクトごとにグループ化し、プロパティを並べ替えます。
[
{
"item": "item1",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue"
]
},
{
"type": "itemtype",
"colour": [
"grey"
]
}
]
},
{
"item": "item2",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue"
]
},
{
"type": "itemtype2",
"colour": [
"orange"
]
},
{
"type": "itemtype2",
"colour": [
"blue"
]
}
]
},
{
"item": "item3",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue"
]
}
]
}
]
私の課題は、これらの入れ子になった属性を一緒にグループ化し、型別にグループ化し、型に応じて配列に色を追加することです。たとえば、次のようなものがあります。
[
{
"item": "item1",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue",
"grey"
]
}
]
},
{
"item": "item2",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue"
]
},
{
"type": "itemtype2",
"colour": [
"orange",
"blue"
]
}
]
},
{
"item": "item3",
"attributes": [
{
"type": "itemtype",
"colour": [
"blue"
]
}
]
}
]
よりよく理解するために、LodashまたはJMESPathのオンラインエディタを試してみましたが、map()
そこに他のエディタを追加しようとしましたが、進歩はmap(.attributes[])
ありませんでした。どこかにReduce()を追加する必要があるようですが、私は知りません。
ありがとうございます!
答え1
この質問をお寄せいただきありがとうございます。一緒に働いて楽しかったです。
以下は何もないバリエーションですreduce
。
group_by(.item) |
map({
item: first.item,
attributes: (
group_by(.attributes[].type) |
map({
type: first.attributes[].type,
colour: ( map(.attributes[].colour[]) )
})
)
})
まず、元の要素をキーにグループ化しますitem
。これは私たちにグループごとの配列を提供しますitem
。この配列の各要素には同じitem
。
最初は、map()
各グループのオブジェクトを作成し、グループを1つにまとめます。オブジェクトにはキーitem
とattributes
キーがあり、キー値はitem
グループの最初の要素からランダムに取得されます(すべて同じ)。
さらに、キーの値を生成group_by()
します。今回は、ソースオブジェクトの配列のキーがグループ化され、生成されたグループごとにソースオブジェクトから合計値が収集されます。map()
attributes
type
attributes
type
colour
以下を使用してこれを実行することもできますreduce
。
group_by(.item) |
map(reduce .[] as $a ({}; .item = $a.item | .attributes += $a.attributes)) |
map(.attributes |= (
group_by(.type) |
map(reduce .[] as $a ({}; .type = $a.type | .colour += $a.colour))
))
これはgroup_by()
、結果の外部構造を作成することに関連しています。つまり、map(reduce)
データを複数の部分にグループ化し、外部構造に従って構成することです。配列item
の値はattributes
単に渡されます。
次に、各グループの配列に対してこのパターン(+)を繰り返し、group_by()
値に基づいてグループ化して構成します。map(reduce)
attributes
type
パフォーマンスの観点から小さい入力の場合、上記の2つの解決策は互いに似ていますが、reduce
問題のサイズ(約64KB)より150倍小さい入力の場合、2番目のバリエーション(使用)はわずかに高速です。これらのサイズ入力の場合、私のシステムで実行するのに約70ミリ秒かかります。これは無視できるランタイムです。
入力が大きくなるとreduced
。入力サイズが4 MBの場合、最初のコードは約800ミリ秒かかりますが、2番目のコードは単一の実行に25秒かかります。
より大きな入力で実行するのが難しい場合jq
(線形外挿法によると、1 GBのデータセットを実行するのに約54時間かかります)以外の方法(おそらくデータベースまたは少なくとも職場)でデータを処理することを検討できます。フォーマット)。
たとえば、与えられたデータをCSVに変換できます。
item,type,colour
item1,itemtype,blue
item1,itemtype,grey
item2,itemtype,blue
item2,itemtype2,orange
item2,itemtype2,blue
item3,itemtype,blue
...または同等のデータベーステーブルに移動してそこで作業します。
ミラーを例に挙げましょう。
$ mlr --csv nest --ivar ';' -f colour file.csv
item,type,colour
item1,itemtype,blue;grey
item2,itemtype,blue
item2,itemtype2,orange;blue
item3,itemtype,blue