...на Kotlin разумеется. В комментариях к предыдущей статье было задано несколько вопросов, как сделать конвертацию в tsv, почему утилита собрана в Docker образ и предложение использовать нативный образ GraalVM.  В этой статье содержится ответ на них и заодно рассказывается о последнем обновлении функций утилиты. Кто по работе часто занимается процессингом JSON - добро пожаловать под кат. Первое о чем хотелось бы рассказать, так это о полной поддержке Kotlin в последнем обновлении утилиты. Выглядит это так: В качестве цепочки выражений можно использовать любые расширения последовательностей. Например, можно использовать их чтобы получить преобразование из предыдущего примера: Если кого-то смущает типизация в этих примерах, то напомню что вместо любого типа можно использовать .obj("name") чтобы получить сырое значение из json как оно есть. Кроме этого, мы все еще можем использовать dsl запросов из первой статьи. С ним наш предыдущий пример будет выглядеть проще: Таким образом, любые преобразования доступны внутри выражений .map{ } и select{ } Проведя эксперименты, убедился что интструмент native-image из GraalVM все еще не готов к использованию: при сборке потерялась часть runtime зависимостей и утилита перестала обнаруживать нужный для интерпретации запросов класс. Поэтому тем кто предпочитает использовать одну команду вместо docker контейнера могу предложить следующее решение: Нам потребуется jvm16+ jar файл утилиты который можно скачать здесь Пара строчек в терминале и получаем команду kq: Последняя версия также доступна и в Docker, кроме него никаких зависимостей не требуется, эту команду без установки можно использовать в любой директории, а ресурсы будут освобождены после исполнения: Благодаря использованию стандартных последовательностей Kotlin вместо самописных, стало возможным сократить весь код утилиты до одного файла из (!) 41 строки не считая импортов. Теперь в коде все запросы просто конкатенируются с последовательностью строк: lines.map(json::readTree) $query и отправляется на исполнение. Просто? Даже очень. Однако это работает лучше предыдущего варианта и возможно еще эффективнее за счет внутренних оптимизаций Kotlin sequences. Любой запрос состоит из набора инструкций и выражений расположенных внутри. В общем виде: В качестве инструкций нам доступно все что есть в стандартной библиотеке Kotlin sequences. Это такие инструкции как filter, map, reduce, take, drop,  и другие. Они должны следовать друг за другом начинаясь с точки как в примерах выше. Внутри таких инструкций, в выражении, текущий объект доступен под именем it Однако дополнительно определены следующие запросы, для которых ставить точку вначале необязательно: Внутри этих последовательностей в качестве выражения мы по прежнему используем Kotlin, однако текущий объект в них будет доступен через ключевое слово this, которое, в отличии от it можно просто опускать и не писать. Также, в этих выражениях, нам доступны следующие функции: Обязательно ли использовать типизацию? Нет. Однако она дает нам возможность использовать для соответствующих типов методы java, например, для временых меток возможно использовать следующее выражение Здесь мы получили топ три самых длительных промежутков времени из ndjson. Без дополнений которые нам дает типизация это было бы почти невозможно (попробуйте провернуть в jq). Например, у нас есть ndjson с вложенными объектами, пример такой записи развернуто: Например, нам нужен топ по навыкам Ивановых в tsv. Нет ничего проще: И да простят меня все Ивановы за этот надуманный пример. Что насчет использования из командой строки? Не будет ли сложнее jq? Судите сами: Репозиторий доступен на GitHubЕсть страничка jar релизовЕсть готовый образ-утилита на DockerHub С++ разработчик