Ефективно шукайте відсортований файл


12

У мене великий файл, що містить один рядок у кожному рядку. Я хотів би мати можливість швидко визначити, чи є рядок у файлі. В ідеалі це можна зробити за допомогою алгоритму типу двійкового відбивання.

Деякі Googling виявили lookкоманду з -bпрапором, яка обіцяє знайти та вивести всі рядки, починаючи з заданого префікса, використовуючи алгоритм двійкового пошуку. На жаль, це, здається, не працює належним чином, і повертає нульові результати для рядків, які я знаю, є у файлі (вони належним чином повертаються при еквівалентному grepпошуку).

Хтось знає про іншу утиліту або стратегію для ефективного пошуку цього файлу?


У верхній відповіді зазначено неправильне сортування: факт полягає в тому, що ви повинні сортувати: LC_COLLATE = С сортувати -d, щоб lookкоманда функціонувала правильно, тому що зовнішній вигляд ігнорує локаль і просто використовує C, як сортування жорстко кодованого, я також відкрив помилку через цю заплутану поведінку: bugzilla.kernel.org/show_bug.cgi?id=198011
Sur3

look -bне вдалося для мене з помилкою File too large. Я думаю, що це намагається прочитати всю річ на пам'ять.
Брайан Мінтон

Відповіді:


9

Існує істотна різниця між grepта look:

Якщо прямо не вказано інше, grepви знайдете візерунки навіть десь у рядках. Для сторінки lookсторінки вказано:

look - відображення рядків, що починаються з заданого рядка

Я використовую не lookдуже часто, але це добре спрацювало на тривіальному прикладі, який я тільки що спробував.


1
Файл, який мені потрібно шукати, містить близько 110 000 000 рядків. Якщо я egrep "^TEST" sortedlist.txt | wc -l отримаю, я отримаю 41,289 результатів. Однак еквівалентні lookкоманди look -b TEST sortedlist.txt | wc -lдають лише 1995 результат. Мені майже цікаво, чи є помилка look.
Метт

1
@Matt Можливо look, використовує різні налаштування порівняння, ніж програма, яку ви використовували для сортування файлу.
kasperd

4

Можливо, трохи пізня відповідь:

Sgrep допоможе вам.

Sgrep (відсортований греп) шукає впорядковані вхідні файли для рядків, які відповідають клавіші пошуку та виводить відповідні рядки. При пошуку великих файлів sgrep відбувається набагато швидше, ніж у традиційних файлів Unix, але зі значними обмеженнями.

  • Усі вхідні файли повинні бути відсортовані звичайними файлами.
  • Клавіша сортування повинна починатися на початку рядка.
  • Ключ пошуку відповідає лише на початку рядка.
  • Немає регулярної підтримки вираження.

Ви можете завантажити джерело тут: https://sourceforge.net/projects/sgrep/?source=typ_redirect

і документи тут: http://sgrep.sourceforge.net/

Інший спосіб:

Я не знаю, наскільки великий файл. Можливо, ви повинні спробувати паралельно:

/programming/9066609/fastest-possible-grep

Я завжди роблю grep з файлами, розмір яких> 100 Гб, це добре працює.


2
Хіба це вже не в askubuntu.com/a/701237/158442 ?
муру

так, я заповнюю посилання для завантаження ...
boxbox

Якщо це все, вам слід відредагувати цю публікацію, а не публікувати нову відповідь.
муру

цей пост рекомендував: sudo apt-get install sgrep щоб отримати sgrep, sgrep у сховищах buntu насправді не є цією сгрепою, я не впевнений, що це те саме.
скринька пам’яті

0

Ви можете розім’яти файл на шматки, а потім обклеїти потрібну частину:

for line in $(cat /usr/share/dict/american-english | tr '[:upper:]' '[:lower:]' | sort | uniq)
do
    prefix=$(echo $line | md5sum - | cut -c 1-2)
    mkdir -p $prefix
    echo $line | gzip >> $prefix/subwords
done

тоді пошук виглядатиме так:

    prefix=$(echo $word | md5sum - | cut -c 1-2)
    zgrep -m 1 -w word $prefix/subwords

Це робить дві речі:

  1. читати і записувати стислі файли. Зазвичай швидше покласти навантаження на процесор (дуже швидко) замість диска (дуже повільно)
  2. хеш-речей, щоб отримати приблизно рівний розподіл, ви можете використовувати коротший або довший хеш, як хочете, щоб зменшити розмір кожної частини (але я рекомендую використовувати вкладені підкаталоги, якщо це зробити)

0

sgrep може працювати для вас:

sudo apt-get install sgrep
sgrep -l '"needle"' haystack.txt

На сторінці проекту http://sgrep.sourceforge.net/ написано:

Sgrep використовує двійковий алгоритм пошуку, який дуже швидкий, але вимагає відсортованого введення.

Однак для вставки я думаю, що немає кращого рішення, ніж використання бази даних: /programming/10658380/shell-one-liner-to-add-a-line-to-a-sorted-file/ 33859372 # 33859372


3
У sgrepсховищах Ubuntu насправді є ця сгреп , яка призначена для "пошуку у файлі за структурованою схемою" і не має нічого спільного з двійковим пошуком.
ingomueller.net

0

Якщо ви хочете, щоб це було дуже швидко (O (1) fast), ви можете створити хеш-набір, який слід вивчити. Я не зміг знайти реалізацію, яка дозволила б мені зберегти заздалегідь вбудований хеш-набір у файл і пробувати його, не змушуючи читати весь файл у пам’яті, тому я прокрутив власний .

Побудуйте хеш-набір ( -b/ --build):

./hashset.py --build string-list.txt strings.pyhashset

Пробний хеш-набір ( -p/ --probe):

./hashset.py --probe strings.pyhashset \
    'Is this string in my string list?' 'What about this one?'

… Або з рядком для пошуку на стандартному вході:

printf '%s\n' 'Is this string in my string list?' 'What about this one?' |
./hashset.py --probe strings.pyhashset

Ви можете увімкнути вихід --probeз параметром -q/, --quietякщо вас цікавить лише статус виходу:

if ./hashset.py --quiet --probe strings.pyhashset ...; then
    echo 'Found'
else
    echo 'Not found'
fi

Для отримання додаткових опцій див. Опис використання, доступний через -h/ --helpoption або супровідний READMEфайл.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.