저는 대규모 JSON 데이터 세트(1GB 이상)로 작업 중이며 유사한 배열 개체를 병합한 다음 중첩된 유사한 개체를 병합해야 합니다. 먼저 다음과 같은 줄이 있습니다.
[{"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[]) )
})
)
})
먼저 원본 요소를 key 로 그룹화합니다 item
. 이것은 우리에게 그룹별 배열을 제공합니다 item
. 이 배열의 각 요소에는 동일한 item
.
첫 번째는 map()
각 그룹에 대한 개체를 만들어 그룹을 하나로 묶습니다. 객체에는 키 item
와 attributes
키가 있으며 키 값은 item
그룹의 첫 번째 요소에서 임의로 가져옵니다(모두 동일함).
더 나아가서 key 에 대한 값을 생성 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
성능 측면에서 작은 입력의 경우 위의 두 솔루션은 서로 비슷하지만 reduce
문제 크기(약 64KB)보다 150배 작은 입력의 경우 두 번째 변형(사용)이 약간 더 빠릅니다. 이러한 크기 입력의 경우 내 시스템에서 실행하는 데 약 70밀리초가 소요되며 이는 무시할 수 있는 런타임입니다.
입력이 더 커지면 reduced
. 입력 크기가 4MB인 경우 첫 번째 코드는 약 800밀리초가 걸리는 반면, 두 번째 코드는 단일 실행에 25초가 걸립니다.
더 큰 입력으로 실행하기 어려운 경우 jq
(선형 외삽법에 따르면 1GB 데이터 세트를 실행하는 데 약 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