Pesquisar com eficiência o arquivo classificado

12

Eu tenho um arquivo grande contendo uma string em cada linha. Eu gostaria de poder determinar rapidamente se uma string está no arquivo. Idealmente, isso seria feito usando um algoritmo binário do tipo chop.

Alguns pesquisadores do Google revelaram o lookcomando com a -bbandeira que promete localizar e gerar todas as strings que começam com um determinado prefixo usando um algoritmo de pesquisa binária. Infelizmente, ele não parece funcionar corretamente e retorna resultados nulos para as seqüências que eu sei que estão no arquivo (elas são retornadas corretamente pela greppesquisa equivalente ).

Alguém conhece outro utilitário ou estratégia para pesquisar esse arquivo com eficiência?

Matt
fonte
A resposta principal indica a classificação errada: o fato é que você deve classificar com: LC_COLLATE = C sort -d para que o lookcomando funcione corretamente, porque o look parece ignorar o código do idioma e apenas usa C como a classificação codificada, também abri um bug por causa deste comportamento confuso: bugzilla.kernel.org/show_bug.cgi?id=198011
Sur3
look -bfalhou para mim com um erro File too large. Eu acho que está tentando ler a coisa toda na memória.
27418 Brian Minton

Respostas:

9

Há uma diferença essencial entre grepe look:

Salvo indicação explícita em contrário, grepele encontrará padrões mesmo em algum lugar dentro das linhas. Para lookos estados da página de manual:

look - exibe linhas que começam com uma determinada string

Não estou usando com lookmuita frequência, mas funcionou bem em um exemplo trivial que acabei de tentar.

Klaus-Dieter Warzecha
fonte
1
O arquivo que preciso pesquisar possui cerca de 110.000.000 de linhas. Se eu egrep "^TEST" sortedlist.txt | wc -l obtiver 41.289 resultados. No entanto, os lookcomandos equivalentes look -b TEST sortedlist.txt | wc -lproduzem apenas resultados de 1995. Eu quase me pergunto se há algum erro look.
22414 Matt
1
@ Matt Talvez lookesteja usando configurações de agrupamento diferentes do programa usado para classificar o arquivo.
kasperd
4

Talvez uma resposta um pouco tarde:

Sgrep irá ajudá-lo.

O Sgrep (grep classificado) procura nos arquivos de entrada classificados as linhas que correspondem a uma chave de pesquisa e gera as linhas correspondentes. Ao pesquisar arquivos grandes, o sgrep é muito mais rápido que o grep tradicional do Unix, mas com restrições significativas.

  • Todos os arquivos de entrada devem ser classificados como arquivos regulares.
  • A chave de classificação deve começar no início da linha.
  • A chave de pesquisa corresponde apenas ao início da linha.
  • Não há suporte para expressões regulares.

Você pode fazer o download da fonte aqui: https://sourceforge.net/projects/sgrep/?source=typ_redirect

e os documentos aqui: http://sgrep.sourceforge.net/

Outra maneira:

Não sei qual é o tamanho do arquivo.Talvez você deva tentar em paralelo:

/programming/9066609/fastest-possible-grep

Eu sempre faço grep com arquivos com tamanho> 100 GB, funciona bem.

caixa de memória
fonte
2
Isso já não está no askubuntu.com/a/701237/158442 ?
muru
Sim, eu preencher o link de download ...
memorybox
Se isso é tudo, você deve editar essa postagem em vez de postar uma nova resposta.
muru
o post recomendado: sudo apt-get install sgrep para obter o sgrep, o sgrep nos repositórios do buntu não é realmente esse sgrep, não tenho certeza se é a mesma coisa.
memorybox
0

Você pode fazer o hash do arquivo em pedaços e depois fazer o grep exatamente o que você deseja:

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

a pesquisa ficaria assim:

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

Isso faz duas coisas:

  1. ler e gravar arquivos compactados. Geralmente é mais rápido colocar a carga na CPU (muito rápido) em vez do disco (muito lento)
  2. hash para obter uma distribuição aproximadamente igual, você pode usar um hash mais curto ou mais longo, conforme desejar, a fim de reduzir o tamanho de cada peça (mas eu recomendo o uso de subdiretórios aninhados, se o fizer)
Joe
fonte
0

O sgrep pode funcionar para você:

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

A página do projeto http://sgrep.sourceforge.net/ diz:

O Sgrep usa um algoritmo de busca binária, que é muito rápido, mas requer entrada classificada.

Para inserção, no entanto, acho que não há solução melhor do que usar um banco de dados: /programming/10658380/shell-one-liner-to-add-a-line-to-a-sorted-file/ 33859372 # 33859372

Ciro Santilli adicionou uma nova foto
fonte
3
O sgrepnos repositórios do Ubuntu é na verdade esse sgrep , que é projetado para "procurar um arquivo em busca de um padrão estruturado" e não tem nada a ver com a pesquisa binária.
ingomueller.net
0

Se você quiser muito rápido (O (1) rápido), poderá criar um conjunto de hash para analisar. Não consegui encontrar uma implementação que me permitisse armazenar um conjunto de hash pré-criado em um arquivo e sondá-lo sem ter que ler o arquivo inteiro na memória, então rolei o meu .

Crie o conjunto de hash ( -b/ --build):

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

Teste o conjunto de hash ( -p/ --probe):

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

… Ou com uma string para procurar na entrada padrão:

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

Você pode silenciar a saída --probecom a opção -q/ --quietse estiver interessado apenas no status de saída:

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

Para mais opções, consulte a descrição de uso acessível por meio da opção -h/ --helpou do READMEarquivo que o acompanha .

David Foerster
fonte