jq 중첩 축소/JSON 데이터 그룹화

jq 중첩 축소/JSON 데이터 그룹화

저는 대규모 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()각 그룹에 대한 개체를 만들어 그룹을 하나로 묶습니다. 객체에는 키 itemattributes키가 있으며 키 값은 item그룹의 첫 번째 요소에서 임의로 가져옵니다(모두 동일함).

더 나아가서 key 에 대한 값을 생성 group_by()하십시오 . 이번에는 원본 개체 배열의 키가 그룹화되고 생성된 각 그룹에 대해 원본 개체에서 합계 값이 수집됩니다.map()attributestypeattributestypecolour


다음을 사용하여 이 작업을 수행할 수도 있습니다 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)attributestype


성능 측면에서 작은 입력의 경우 위의 두 솔루션은 서로 비슷하지만 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

관련 정보