Сглаживание вложенного JSON с помощью jq

#json #jq

Вопрос:

Я хотел бы сгладить вложенный объект json, например {"a":{"b":1}} {"a.b":1} , чтобы переварить его в solr.

У меня есть 11 ТБ файлов json, которые являются вложенными и содержат точки в именах полей, что означает, что ни elasticsearch (точки), ни solr (вложенные без _childDocument_ обозначения) не могут переварить их как есть.

Другими решениями было бы заменить точки в именах полей подчеркиванием и перенести их в elasticsearch, но у меня гораздо лучший опыт работы с solr, поэтому я предпочитаю сглаживающее решение (если только solr не может переварить эти вложенные json, как есть??).

Я предпочту elasticsearch только в том случае, если процесс переваривания займет гораздо меньше времени, чем solr, потому что мой приоритет-переваривать как можно быстрее (поэтому я выбрал jq вместо написания сценария на python).

Пожалуйста, помогите.

Редактировать:

Я думаю, что пара примеров 3 и 4 решает эту проблему для меня: https://lucidworks.com/blog/2014/08/12/indexing-custom-json-data/

Я скоро попробую.

Ответ №1:

Вы также можете использовать следующую команду jq для выравнивания вложенных объектов JSON таким образом:

 [leaf_paths as $path | {"key": $path | join("."), "value": getpath($path)}] | from_entries
 

Это работает следующим образом: leaf_paths возвращает поток массивов, представляющих пути в данном документе JSON, в котором отображаются «конечные элементы», то есть элементы, у которых нет дочерних элементов, таких как числа, строки и логические значения. Мы передаем этот поток в объекты со key value свойствами и, где key содержит элементы массива путей в виде строки, соединенной точками, и value содержит элемент на этом пути. Наконец, мы помещаем все это в массив и запускаем from_entries на нем, который преобразует массив {key, value} объектов в объект, содержащий эти пары ключ-значение.

Комментарии:

1. Это решение не работает, если JSON содержит массивы. Например: {"a":{"b":[1]}} для которого возникает ошибка: jq: ошибка (при <stdin>:1): строка («.») и число (0) не могут быть добавлены<stdin>

2. Отличный ответ, хотя это отфильтровывает любые значения , которые оцениваются false , false т. Е. null , и т. Д. Это связано с тем , что leaf_paths это короткая рука для paths(scalars) , и хотя scalars она выбирает их, paths возвращает только те записи, для которых они не являются ложными. Короче говоря, замените leaf_paths , paths(type != "object" and type != "array") чтобы включить все.

3.Чтобы исправить ошибку jq: ошибка (в <stdin>:1): строка («.») и число (0) не могут быть добавлены<stdin> [leaf_paths as $path | {"key": [$path[] | tostring] | join("."), "value": getpath($path)}] | from_entries

Ответ №2:

Это всего лишь вариант jq Сантьяго:

 . as $in 
| reduce leaf_paths as $path ({};
     .   { ($path | map(tostring) | join(".")): $in | getpath($path) })
 

Это позволяет избежать накладных расходов на создание и уничтожение ключа/значения.

(Если у вас есть доступ к версии jq более поздней, чем jq 1.5, вы можете опустить «map(tostring)».)

Два важных момента в отношении обоих этих решений jq:

  1. Массивы также сглажены. Например {"a": {"b": [0,1,2]}} , в качестве входных данных вывод будет:
     {
      "a.b.0": 0,
      "a.b.1": 1,
      "a.b.2": 2
    }
     
  2. Если какой-либо из ключей в исходном JSON содержит точки, то возможны коллизии ключей; такие коллизии, как правило, приводят к потере значения. Это могло бы произойти, например, при следующем вводе:
     {"a.b":0, "a": {"b": 1}}
     

Комментарии:

1. @SteveAmerige — Ответ был обновлен, чтобы он работал с jq 1.4 и более поздними версиями.

Ответ №3:

Вот решение, которое использует для поиска, выбора, объединения, уменьшения и установки пути

   reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] (
     {}
     ; setpath($p; $v)
  )
 

Ответ №4:

Недавно я написал сценарий под названием jqg, который сглаживает произвольно сложный JSON и выполняет поиск результатов с помощью регулярного выражения; чтобы просто сгладить JSON, ваше регулярное выражение будет» . , что соответствует всему. В отличие от ответов выше, сценарий будет обрабатывать встроенные массивы false и null значения и может при необходимости обрабатывать пустые массивы и объекты ( [] amp; {} ) в качестве конечных узлов.

 $ jq . test/odd-values.json
{
  "one": {
    "start-string": "foo",
    "null-value": null,
    "integer-number": 101
  },
  "two": [
    {
      "two-a": {
        "non-integer-number": 101.75,
        "number-zero": 0
      },
      "true-boolean": true,
      "two-b": {
        "false-boolean": false
      }
    }
  ],
  "three": {
    "empty-string": "",
    "empty-object": {},
    "empty-array": []
  },
  "end-string": "bar"
}

$ jqg . test/odd-values.json
{
  "one.start-string": "foo",
  "one.null-value": null,
  "one.integer-number": 101,
  "two.0.two-a.non-integer-number": 101.75,
  "two.0.two-a.number-zero": 0,
  "two.0.true-boolean": true,
  "two.0.two-b.false-boolean": false,
  "three.empty-string": "",
  "three.empty-object": {},
  "three.empty-array": [],
  "end-string": "bar"
}
 

jqg был протестирован с использованием jq 1.6

Примечание: Я являюсь автором jqg сценария.

Ответ №5:

Как выясняется, curl -XPOST 'http://localhost:8983/solr/flat/update/json/docs' -d @json_file делает именно это:

 {
    "a.b":[1],
    "id":"24e3e780-3a9e-4fa7-9159-fc5294e803cd",
    "_version_":1535841499921514496
}
 

ПРАВКА 1: solr 6.0.1 с. bin/solr -e cloud имя коллекции есть flat , все остальные по умолчанию (с data-driven-schema которым также по умолчанию).

ПРАВКА 2: Окончательный сценарий, который я использовал: find . -name '*.json' -exec curl -XPOST 'http://localhost:8983/solr/collection1/update/json/docs' -d @{} ; .

ПРАВКА 3: Также возможно параллелизировать с xargs и добавить поле идентификатора с jq: find . -name '*.json' -print0 | xargs -0 -n 1 -P 8 -I {} sh -c "cat {} | jq '. {id: .a.b}' | curl -XPOST 'http://localhost:8983/solr/collection/update/json/docs' -d @-" где -P коэффициент параллелизма. Я использовал jq для установки идентификатора, чтобы несколько загрузок одного и того же документа не создавали дубликатов в коллекции (когда я искал оптимальное значение -P , оно создавало дубликаты в коллекции).