Ricerca efficiente di file ordinati


12

Ho un file di grandi dimensioni contenente una stringa su ogni riga. Vorrei essere in grado di determinare rapidamente se una stringa è nel file. Idealmente, questo dovrebbe essere fatto usando un algoritmo binario di tipo chop.

Alcuni googling hanno rivelato il lookcomando con il -bflag che promette di localizzare e produrre tutte le stringhe che iniziano con un dato prefisso usando un algoritmo di ricerca binaria. Sfortunatamente, non sembra funzionare correttamente e restituisce risultati nulli per le stringhe che so siano nel file (sono correttamente restituite dalla grepricerca equivalente ).

Qualcuno conosce un'altra utility o strategia per cercare questo file in modo efficiente?


La risposta principale indica l'ordinamento errato: il fatto è che devi ordinare con: LC_COLLATE = C sort -d affinché il lookcomando funzioni correttamente, perché look sembra ignorare le impostazioni locali e usa solo C come ordinamento hardcoded, ho anche aperto un bug a causa di questo comportamento confuso: bugzilla.kernel.org/show_bug.cgi?id=198011
Sur3

look -bfallito per me con un errore File too large. Penso che stia cercando di leggere tutto in memoria.
Brian Minton,

Risposte:


9

C'è una differenza essenziale tra grepe look:

Se non diversamente specificato, greptroveranno schemi anche da qualche parte all'interno delle linee. Per lookgli stati manpage:

look: visualizza le righe che iniziano con una determinata stringa

Non sto usando lookmolto spesso, ma ha funzionato bene su un esempio banale che ho appena provato.


1
Il file che devo cercare ha circa 110.000.000 di righe. Se lo faccio egrep "^TEST" sortedlist.txt | wc -l ottengo 41.289 risultati. Tuttavia, i lookcomandi equivalenti , look -b TEST sortedlist.txt | wc -lproducono solo 1995 risultati. Mi chiedo quasi se ci sia un bug look.
Matt,

1
@Matt Forse looksta utilizzando impostazioni di confronto diverse rispetto al programma utilizzato per ordinare il file.
Kasperd,

4

Forse una risposta un po 'in ritardo:

Sgrep ti aiuterà.

Sgrep (grep ordinato) cerca nei file di input ordinati le righe che corrispondono a una chiave di ricerca e genera le righe corrispondenti. Durante la ricerca di file di grandi dimensioni sgrep è molto più veloce del tradizionale grex Unix, ma con restrizioni significative.

  • Tutti i file di input devono essere ordinati file regolari.
  • La chiave di ordinamento deve iniziare all'inizio della riga.
  • La chiave di ricerca corrisponde solo all'inizio della riga.
  • Nessun supporto per le espressioni regolari.

Puoi scaricare la fonte qui: https://sourceforge.net/projects/sgrep/?source=typ_redirect

e i documenti qui: http://sgrep.sourceforge.net/

Un altro modo:

Non so quanto sia grande il file. Forse dovresti provare in parallelo:

/programming/9066609/fastest-possible-grep

Faccio sempre grep con file di dimensioni> 100 GB, funziona bene.


2

sì,
compilo il

Se è tutto, dovresti modificare quel post invece di pubblicare una nuova risposta.
muru,

quel post consigliato: sudo apt-get install sgrep per ottenere sgrep, lo sgrep nei repository di buntu non è in realtà questo sgrep, non sono sicuro che sia la stessa cosa.
memorybox

0

Puoi tagliare il file in pezzi e poi grep solo il pezzo che volevi:

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

quindi la ricerca sarebbe simile a:

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

Questo fa due cose:

  1. leggere e scrivere file compressi. In genere è più veloce caricare il carico sulla CPU (molto velocemente) invece che sul disco (molto lento)
  2. hash cose per ottenere una distribuzione approssimativamente uguale, puoi usare un hash più corto o più lungo che desideri per ridurre le dimensioni di ogni pezzo (ma in tal caso ti consiglio di usare i sottodirectory nidificati)

0

sgrep potrebbe funzionare per te:

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

La pagina del progetto http://sgrep.sourceforge.net/ dice:

Sgrep utilizza un algoritmo di ricerca binaria, che è molto veloce, ma richiede un input ordinato.

Per l'inserimento, tuttavia, penso che non esista una soluzione migliore dell'utilizzo di un database: /programming/10658380/shell-one-liner-to-add-a-line-to-a-sorted-file/ 33859372 # 33859372


3
Il sgrepnei repository Ubuntu è in realtà questo sgrep , che è progettato per "cercare un file in un modello strutturato" e non ha nulla a che fare con la ricerca binaria.
ingomueller.net,

0

Se lo vuoi davvero veloce (O (1) veloce) puoi costruire un set di hash da esaminare. Non sono riuscito a trovare un'implementazione che mi permettesse di archiviare un set di hash pre-costruito in un file e di sondarlo senza dover leggere l'intero file in memoria, quindi ho creato il mio .

Crea l'hash set ( -b/ --build):

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

Sonda l'hash set ( -p/ --probe):

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

... o con stringa per cercare in input standard:

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

Puoi silenziare l'output di --probecon l' opzione -q/ --quietse sei interessato solo allo stato di uscita:

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

Per ulteriori opzioni, consultare la descrizione dell'utilizzo accessibile tramite l' opzione -h/ --helpo il READMEfile di accompagnamento .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.