Задать вопрос
sovadeveloper
@sovadeveloper

Как написать свой парсер (поисковик) CSV на Java?

как написать свой парсер CSV файлов, который будет искать подходящие строки по введенной строке и колонке, после чего возвращать все подходящие результаты.
Важно, что нельзя:
1) Использовать готовые библиотеки для работы с CSV
2) Сохранять весь файл ни в какую-либо структуру, ни как массив байт
3) Использовать БД или как-либо менять (создавать новые) файлы
4) Перечитывать полностью весь CSV файл каждый раз (и даже отдельные колонки)

Так же необходимо, что бы сложность была < O(n)

У меня уже есть некоторое решение, а именно решил так: читаю файл, сравниваю с введенной строкой, и кеширую, если в кеше уже есть такой ключ (кеш реализовал с помощью LinkedHashMap, где ключ - значение конкретной колонки из CSV файла, а значение - вся строка), то в результирующий List добавляю значение из кеша, а если же нет, то во-первых, записываю в кеш, а во-вторых, добавляю все в тот же результирующий List.
Но у этого подхода есть минусы, во-первых, тут не выполняется условие, что нельзя перечитывать весь файл каждый раз, так как в моей реализации это делается, как минимум для того, что бы сравнить есть ли это уже в кеше или нет. Во-вторых, первые 1-3 запуска (там в цикле вводишь символы для поиска) даже если одни и те же вводить, первые 1-3 раза, поиск долгий, а после этого уже нормальный (первые разы может быть 50-70мс, а последующие 15-25мс)

Рассматривал еще такой вариант: бинарный поиск - берем читаем файл, после чего по нужной колонке сортируем, ищем нужные значения и отдаем результат. Но сразу вижу проблему, что не пройду по условие сложность < O(n), так как фильтрация будет уже O(n)

Я не прошу решить за меня если что) Мне бы задать вектор, что почитать, что посмотреть, потому что какое-то более хорошее решение придумать не получается...
  • Вопрос задан
  • 850 просмотров
Подписаться 2 Средний 4 комментария
Пригласить эксперта
Ответы на вопрос 2
@rPman
Важно, что нельзя:
2) Сохранять весь файл ни в какую-либо структуру, ни как массив байт

извини, но если хочешь высокой скорости, какую то информацию сохранить придется

Ускорение возможно только за счет траты памяти, сохраняя какую то информацию.

Варианты:
1. ускорить примерно 'в константу раз' можно, исключив проблемы с парсингом csv формата, т.е. сохранив информацию о координатах каждой строки и даже его элементах (ты должен хранить смещение в файле для каждой следующей строки и размеры/смещения каждой колонки относительно начала строки, особенно это актуально для строковых значений, экранирование символов " и \n тратит время на парсинг)
2. хранение информации о типах данных может так же заметно увеличить чтение данных из файла, причем речь не только о просто знании структуры (какая колонка какой тип ожидается) но и о фактическом значении в каждой строке (например факты расхождения с ожидаемой структурой), но это уже от задачи, редко когда требуется гибкая типизация, и как минимум, знание о том что строка требует или не требует обработку экранирования может ускорить это в 2 раза, очень часто это знание может быть заложено в код заранее, без предварительного чтения файла
3. хеширование значений в памяти, дает огромный прирост к поиску данных 'по значению', причем в зависимости от задачи это может быть хеширование как всей строки так и отдельных ее колонок или группы (как частный случай индексирования)
4. построение индексов, еще большая информация о данных, в зависимости от типа индекса, позволяет за константное/логарифмическое время решать такие задачи как поиск max/min/сравнение для числовых данных, или к примеру анализ строковых (например по словам или языковые запросы, т.е. наличие символов из наборов)
p.s. в догонку мелкие оптимизации
- работа с файлом, замапленным на кусок памяти (все ОС это поддерживают) дает огромный прирост по сравнению с чтением по кусочкам и тем более fgets (на самом деле при грамотном fread скорости не на много отличаются но речь просто об удобстве и единообразии кода)
- java это не совсем про хорошую скорость низкоуровневых операций, тут может оказаться что готовые но 'плохие' методы (реализованные на нативном коде) окажутся быстрее правильных идеологически но спотыкающихся о jvm прослойку, там где нужна скорость где действительно приходится так оптимизировать, бери c++, тем более благодаря последним десятилетиям развития std он стал очень и очень удобным не в ущерб скорости.

p.p.s. надо быть очень странным человеком, чтобы хранить данные в csv файле вместо адекватной базы данных с уже готовыми инструментами индексации и поиска.
Настоятельно рекомендую освоить sqlite, в т.ч. как инструмент передачи данных другим людям, так как ну очень достали те кто использует excel или csv, изобретая бредовые форматы сериализации списков и сложных связей, постоянно спотыкаясь об мультиязыковую поддержку, даты и даже банальные символы точка и запятая у вещественных чисел

Кстати у sqlite встроенные механизмы импорта данных из csv, в 1 строчку
Ответ написан
mayton2019
@mayton2019
Bigdata Engineer
Использовать готовые библиотеки для работы с CSV

Я не согласен с этим ограничением. Зачем оно? Так хочет твой преподаватель? Это просто неконструктивно. В процессе написания парсера ты соберешь миллион гвоздей и шишек. Лучше брать готовы парсеры которые работают со скорость канала IO (Univocity например).

Перечитывать полностью весь CSV файл каждый раз (и даже отдельные колонки)

Я не согласен с этим ограничением. Почему нельзя? Цель найти данные. А не банить операции I/O.
Если ты делаешь In-Memory DB то так и напиши. А то получаетася такое завуалированное требовие.
Потому-что решать эту задачу не читая CSV невозможно.

У меня уже есть некоторое решение, а именно решил так: читаю файл, сравниваю с введенной строкой, и кеширую, если в кеше уже есть такой ключ (кеш реализовал с помощью LinkedHashMap

Какая-то ерунда. Откуда здесь берется условие "если" ? Тебе не нужно если, чувак. Тебе нужно 100% данных
положить in-memory сразу во время первого чтения. Причем тебе нужно столько LHM, сколько колонок.

Я не прошу решить за меня если что) Мне бы задать вектор, что почитать, что посмотреть, потому что какое-то более хорошее решение придумать не получается... Спасибо!

Скорее всего нет такого вектора. Но ты должен начать читать с Алгоритмов и Структур данных
Потом почитай про дисковые структуры данных для поиска B+Tree, LSMTree. Почитай как устроены
таблицы в Cassandra (partitionkey, clustering key). Почитай как работает LRU и кеш блоков.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы