Сортировка пользовательского массива со строками дает неправильный порядок, даже если содержимое файла полностью доступно на диске

Я запрашиваю ElasticSearch и сортирую документы локально в Bash с помощью jq, так как сортировка в ES для меня слишком медленная.

Исходная цель — создать файл CSV.

Но я обнаружил, что сортировка не работает должным образом, кажется, шаг sort ничего не делает.

Когда я запускаю запросы cURL, я подумал, что неправильный порядок из-за того, что контент разбит на части, поэтому я сохранил некоторые результаты в локальный файл test.json и попробовал еще раз, но это все равно не работает.

test.json:

{
    "took": 680,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "max_score": 1.0,
        "hits": [
            {
                "_index": "my-index",
                "_type": "_doc",
                "_id": "111111113584925",
                "_score": 1.0,
                "fields": {
                    "field2": [
                        "FOO"
                    ],
                    "field1": [
                        "111111113584925"
                    ]
                }
            },
            {
                "_index": "my-index",
                "_type": "_doc",
                "_id": "111111121254059",
                "_score": 1.0,
                "fields": {
                    "field2": [
                        "FOO"
                    ],
                    "field1": [
                        "111111121254059"
                    ]
                }
            }
        ]
    }
}

(Есть еще много записей - отредактировано для краткости.)

Команда, которую я использую:

jq '.hits.hits[].fields | [.field1[0] + "," + .field2[0]] | sort | .[0]' -r test.json

Результат:

111111113584925,FOO
111111121254059,FOO
111111116879444,FOO

и т. д.

Почему?

Стоит ли мне полагаться на сортировку jq? Правильно ли я его использую? Я имею в виду, что я хочу выполнить сравнение строк в алфавитном порядке, и все field1 имеют уникальные значения, поэтому никогда не будет ничьей, и я начну сравнивать значения field2 (оно также может иметь различные значения, но я хочу сортировать только по field1)

Должен ли я вместо этого использовать Bash sort -k 1? Что быстрее, когда речь идет о 100 тыс. строк?

Если вы посмотрите на промежуточные результаты, вы увидите, что после первого шага у вас есть отдельные объекты, а не массив в качестве элемента верхнего уровня. Затем сортировка применяется к каждому элементу отдельно. Полученные вами ответы позволяют убедиться, что у вас действительно есть массив перед сортировкой.

Benjamin W. 15.05.2024 15:24

См. unix.stackexchange.com/questions/613779/…

Paul Hodges 15.05.2024 15:25

Зачем вы оборачиваете один элемент массива, сортируете, а затем снова разворачиваете элемент массива?

knittl 15.05.2024 15:25
sort работает с массивом в качестве входных данных. Ваши массивы содержат только один элемент, поэтому сортировать нечего. Для сортировки вы передаете не один большой массив массивов, а множество одноэлементных массивов.
knittl 15.05.2024 15:26

Я не очень хорошо знаком с сортировкой в ​​jq, но мне кажется, что было бы так же просто использовать jq '.hits.hits[].fields | .field1[0] + "," + .field2[0]' -r test.json | сортировать -n

Paul Hodges 15.05.2024 15:34

@knittl Я хотел построить из этого массив, но, думаю, это, видимо, не удалось.

WesternGun 15.05.2024 15:35

@WesternGun .hits.hits[].fields | [.field1[0] + "," + .field2[0]] создает поток массивов, например. ["1,FOO"]["2,FOO"]["3,FOO"]. Если вы хотите ["1,FOO","2,FOO","3,FOO"], вам нужно [.hits.hits[].fields | .field1[0] + "," + .field2[0]] или map(…)

knittl 15.05.2024 15:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для сортировки по .fields.field1[0] используйте sort_by(.fields.field1[0]). Но поскольку вы хотите вывести те же значения, которые используются в качестве критериев, уменьшите заранее, используя map, и просто используйте sort в массиве результатов:

jq -r '.hits.hits | map(.fields.field1[0]) | sort[]' file.json

Демо

Обратите внимание, что при этом выполняется сортировка строк, поскольку все первые элементы массива .field1 на самом деле являются строками (несмотря на то, что 11 содержит только цифры, 2 будет отсортирован раньше tonumber). Если вам нужна числовая сортировка (в том смысле, что два меньше одиннадцати), сначала преобразуйте элементы в числа, используя -r. В этом случае вы также можете удалить флаг field1, поскольку числа JSON не имеют специальной кодировки.

jq -r '.hits.hits | map(.fields.field1[0] | tonumber) | sort[]' file.json

Демо

Поскольку демонстрационные данные содержат только строковые элементы одинаковой длины, состоящие только из цифр, оба подхода дают одинаковый результат:

111111113034864
111111113034877
111111113034894
111111113046053
111111113046124
:

Мне нужен CSV-файл, в котором field2 и , разделены sort_by(.fields.field1[0]).

Поскольку элементы вывода отличаются от критериев сортировки, я бы вернулся к использованию @csv, поскольку это дает вам больше свободы для смешивания и сопоставления, и заставил бы .fields.field1[0] сконструировать вывод, который также позаботится об экранировании специальных символов:

.hits.hits | sort_by(.fields.field1[0])[].fields
| [.field1[0], .field2[0]] | @csv
"111111113034864","FOO"
"111111113034877","FOO"
"111111113034894","FOO"
"111111113046053","FOO"
"111111113046124","FOO"

Демо

Спасибо, я думаю, что карта - это путь. Извините, мне придется принять другой вариант, так как мне нужен CSV-файл, в котором field1 и field2 разделены ,; но все равно спасибо

WesternGun 15.05.2024 15:40

В последнем редактировании добавлено еще несколько уровней труб, и это кажется длинным и запутанным; и, наконец, в нем все еще есть цитаты.

WesternGun 16.05.2024 20:52
Ответ принят как подходящий

Вы ищете что-то вроде этого:

.hits.hits | map(.fields | .field1[0] + "," + .field2[0]) | sort[]

Online demo

О, спасибо, это быстро и именно то, что я хочу. Я не знал, что смогу разделить большой массив с помощью sort[]; только с sort у меня получился один большой массив. И кажется, мне нужно остановиться на уровень выше, чтобы начать картографирование. Что за язык. Я не знаю, какая операция выполняется над целым, а какая над каждым элементом.

WesternGun 15.05.2024 15:41

Кстати, у тебя есть представление о перформансе? jq sort против Баша sort

WesternGun 15.05.2024 15:43

Вы всегда можете это сделать … | sort | .[], если так будет легче понять :)

knittl 15.05.2024 15:56

@WesternGun Автономная утилита сортировки будет быстрее для больших входных данных.

oguz ismail 15.05.2024 16:42

@oguzismail да, я только что проверил материалы сортировки, кажется, это сортировка слиянием и так далее.

WesternGun 16.05.2024 20:50

Другие вопросы по теме