phigita.net! Homepage

Γρήγορη Αναζήτηση Σε Αρχεία Χρησιμοποιώντας swish-e

Posted by Χρίστος Ευαγγέλου Sun, 14 Jun 2009 12:48:53 EEST

Την περασμένη εβδομάδα είχα να αντιμετωπίσω ένα ενδιαφέρον πρόβλημα.

Χρησιμοποιώ μια εφαρμογή η οποία παράγει αρχεία (logs) απλού κειμένου, το μέγεθος των οποίων φτάνει καθημερινά (περίπου) το 0.5 GB. Η αποθήκευση δεν είναι πρόβλημα επειδή όταν συμπιεστούν, τα logs μιας μέρας πέφτουν στα 10-20 MB.

Ιδού λοιπόν το πρόβλημα: Συχνά ψάχνω στα logs για να βρω κάποιο κείμενο χρησιμοποιώντας το κλασικό εργαλείο grep του Unix. Αυτό δεν θα ήταν και τόσο πρόβλημα αν διατηρούνταν logs μονάχα για 2-3 μέρες. Εντούτοις, τα logs αυτά διατηρούνται για πολλούς μήνες. Ενδεικτικά, σε ένα μήνα έχουμε περίπου 0.5 * 30 = 15 GB πληροφορίας. Το ψάξιμο με grep (ή με οποιοδήποτε άλλο παρόμοιο εργαλείο αναζήτησης) σε τέτοιο όγκο δεδομένων είναι χρονοβόρο και άρα μη πρακτικό.

Ψάχνοντας λοιπόν, βρήκα ένα open-source εργαλείο το οποίο λέγεται swish-e. Το εργαλείο αυτό, είναι στην ουσία ένας command-line indexer: διαβάζει ένα σύνολο αρχείων και φτιάχνει ένα "πίνακα περιεχομένων" (index), επιτρέποντας έτσι την πολύ γρήγορη αναζήτηση πληροφορίας. Είπα, λοιπόν, να το δοκιμάσω.

Εγκατάσταση

Ξεκίνησα κατεβάζοντας το source-code από την σχετική σελίδα (σημείωση: binaries για Windows υπάρχουν στην ίδια σελίδα).

Αποσυμπίεσα λοιπόν το tarball και έκανα την κλασική διαδικασία που κάνει κάποιος όταν χρειάζεται να κάνει compile από source (configure, make, make install)*:

[root@ ~]# tar -xzf latest.tar.gz
[root@ ~]# cd swish-e-2.4.7/
[root@ ~/swish-e-2.4.7]#

Έτρεξα το configure script για να φτιάξει τα makefiles:

[root@ ~/swish-e-2.4.7]# ./configure
checking for build-swish-docs… no
checking for a BSD-compatible install… /usr/bin/install -c
checking whether build environment is sane… yes

        < . . . και πολλά άλλα . . . >

config.status: creating swish-config
config.status: creating src/acconfig.h
config.status: executing depfiles commands
[root@ ~/swish-e-2.4.7]#
[root@ ~/swish-e-2.4.7]#

Λίγα δευτερόλεπτα μετά, το configure τελείωσε, και ήμουν έτοιμος να μεταγλωττίσω. Έτρεξα λοιπόν την make. Μετά από ένα λεπτό περίπου, η μεταγλώττιση τελείωσε επιτυχώς.

[root@ ~/swish-e-2.4.7]# make
Making all in filters
Making all in SWISH

        < . . . και πολλά άλλα . . . >

creating swish-e
Making all in tests
Making all in pod
[root@ ~/swish-e-2.4.7]#
[root@ ~/swish-e-2.4.7]#

Τέλος, έτρεξα το make install για να αντιγράψει τα binary αρχεία που δημιουργήθηκαν κατά την μεταγλώττιση στα σωστά directories.

[root@ ~/swish-e-2.4.7]# make install
Making install in filters
Making install in SWISH
test -z "/usr/local/lib/swish-e/perl/SWISH" || /usr/local/bin/bash ../../config/mkinstalldirs "/usr/local/lib/swish-e/perl/SWISH"

          < . . . και πολλά άλλα . . . >

test -z "/usr/local/lib/pkgconfig" || /usr/local/bin/bash ./config/mkinstalldirs "/usr/local/lib/pkgconfig"
  /usr/bin/install -c -m 644 'swish-e.pc' '/usr/local/lib/pkgconfig/swish-e.pc'
[root@ ~/swish-e-2.4.7]#
[root@ ~/swish-e-2.4.7]#

Αυτό ήταν! Πάμε λοιπόν να το δοκιμάσουμε τώρα.

Δημιουργία Ευρετηρίου

Το πρώτο βήμα είναι η δημιουργία του ευρετηρίου. Αυτό γίνεται με την εντολή "swish-e -i":

[root@ ~]# swish-e -i /usr/src -f /usr/src/index.swish-e

Η επιλογή -i υποδηλώνει για πια directories ή αρχεία θέλουμε να φτιάξουμε ευρετήριο. Στην περίπτωση μας, είναι το directory /usr/src. Η επιλογή -f υποδηλώνει το όνομα και τοποθεσία του αρχείου-ευρετηρίου το οποίο θα δημιουργηθεί. Αν δεν δοθεί, το ευρετήριο θα δημιουργηθεί στο directory από όπου εκτελείται η εντολή και θα έχει όνομα "index.swish-e".

Τα αποτελέσματα δεν φαίνονταν και πολύ καλά: Υπήρχαν πολλά μηνύματα λάθους, όπως φαίνεται πιο κάτω. Το swish-e δυσκολευόταν να καταλάβει τα περιεχόμενα των διάφορων αρχείων:

[root@ ~]# swish-e -i /usr/src -f /usr/src/index.swish-e
Indexing Data Source: "File-System"
Indexing "/usr/src"
/usr/src/MAINTAINERS:140: error: Tag tab invalid
$ cd /usr/src; find / -type f|xargs egrep 'MAINTAINER[ <tab>]*='
                                                              ^
/usr/src/MAINTAINERS:143: error: error parsing attribute name
sys/modules/urio/Makefile:MAINTAINER=  Iwasa Kazmi  <email protected>
                                                        ^
/usr/src/MAINTAINERS:143: error: Tag kzmi invalid
sys/modules/urio/Makefile:MAINTAINER=  Iwasa Kazmi  <email protected>

          < . . . και πολλά άλλα . . . >

[root@ ~/swish-e-2.4.7]#
[root@ ~/swish-e-2.4.7]#

Ψάχνοντας λιγάκι, κατάλαβα γιατί συμβαίνει αυτό: Εξορισμού, το swish-e υποθέτει ότι τα αρχεία τα οποία επεξεργαζόμαστε περιέχουν κώδικα HTML. Επειδή όμως τα περισσότερα αρχεία κάτω από το /usr/src δεν είναι σε τέτοια μορφή, το swish-e παραπονιόταν.

Αρχείο Ρυθμίσεων

Η λύση ήταν απλή: Το swish-e μπορεί να διαβάσει τις ρυθμίσεις του από ένα αρχείο ρυθμίσεων (configuration file). Εκεί μπορείς να του υποδηλώσεις σε τι μορφή να υποθέσει ότι είναι τα αρχεία εισόδου. Έφτιαξα λοιπόν ένα αρχείο ρυθμίσεων και χρησιμοποίησα την ρύθμιση DefaultContents για να αναγκάσω το swish-e να μεταχειριστεί τα περιεχόμενα των αρχείων εισόδου ως αρχεία απλού κειμένου:

  DefaultContents TXT

Εκτός από TXT, υποστηρίζονται επίσης XML και HTML. Μπορούμε να υποδηλώσουμε την μορφή των αρχείων με βάση το extension τους χρησιμοποιώντας το IndexContents. Για παράδειγμα:

IndexContents TXT .txt .log .text .c .h .java .cpp
IndexContents XML .xml
IndexContents HTML .htm .html .shtml
DefaultContents TXT

Εάν ένα αρχείο δεν έχει extension που να ταιριάζει με κάποιο IndexContents, θα τύχει χειρισμού σύμφωνα με την επιλογή στο DefaultContents.

To swish-e υποστηρίζει τις ακόλουθες μορφές:

  • TXT, HTML, XML: λένε στο swish-e να χρησιμοποιήσει την δική του εσωτερική μηχανή parsing κατά την ανάγνωση των αρχείων.
  • TXT2, HTML2, XML2: λένε στο swish-e να χρησιμοποιήσει την εξωτερική βιβλιοθήκη libxml2 για parsing. Η βιβλιοθήκη θα πρέπει να είναι εγκατεστημένη στο σύστημα.
  • TXT, HTML ή XML με αστερίσκο στο τέλος: λένε στο swish-e να να ανιχνεύσει και να επιλέξει μόνο του πια μηχανή parsing να χρησιμοποιήσει (δεν βάζω αστερίσκους εδώ επειδή ο editor του Phigita τους ερμηνεύει ως εντολές για italic).

Σημείωση: Δεν έκανα δοκιμές για να δω πιο parser είναι πιο γρήγορο.

Δοκιμή

Έτρεξα λοιπόν ξανά το swish-e, λέγοντας του να χρησιμοποιήσει το configuration file το οποίο έφτιαξα μέσω της επιλογής -c. Η διαδικασία ολοκληρώθηκε επιτυχώς μέσα σε περίπου 3.5 λεπτά:

[root@ ~]# swish-e -i /usr/src -f /usr/src/index.swish-e -c ~/swish-e.config
Indexing Data Source: "File-System"
Indexing "/usr/src"
Removing very common words…
no words removed.
Writing main index…
Sorting words …
Sorting 880,685 words alphabetically
Writing header …
Writing index entries …
  Writing word text: Complete
  Writing word hash: Complete
  Writing word data: Complete
880,685 unique words indexed.
4 properties sorted.
37,287 files indexed.  441,169,233 total bytes.  66,775,327 total words.
Elapsed time: 00:03:25 CPU time: 00:01:31
Indexing done!
[root@ ~]#
[root@ ~]#
[root@ ~]# ls -lh /usr/src/index.swish-e*
-rw-r–r–    1 root    wheel        131M Jun 14 13:23 /usr/src/index.swish-e
-rw-r–r–    1 root    wheel        1.9M Jun 14 13:23 /usr/src/index.swish-e.prop
[root@ ~]#
[root@ ~]#

Περίπου, λοιπόν, 440 MB έγιναν index σε 3.5 λεπτά. Το index file ήτανε περίπου 130 MB. Δεν ήτανε και άσχημα.

Πάμε λοιπόν να ψάξουμε για την φράση what the hell. Για ψάξιμο, χρησιμοποιείται η επιλογή -w, ακολουθούμενη από λέξεις ή φράσεις οι οποίες θα αναζητηθούν.

Σημείωση: το swish-e υποστηρίζει πληθώρα μορφών αναζήτησης, μεταξύ των οποίων αναζήτηση λέξεων, φράσεων, τελεστές boolean, wildcards κλπ. Πληρέστερη περιγραφή εδώ.

[root@ ~]# swish-e -w '"what the hell"' -f /usr/src/index.swish-e
# SWISH format: 2.4.7
# Search words: "what the hell"
# Removed stopwords:
# Number of hits: 12
# Search time: 0.158 seconds
# Run time: 0.164 seconds
1000 /usr/src/games/fortune/datfiles/fortunes "fortunes" 2196105
975 /usr/src/games/fortune/datfiles/fortunes-o.real "fortunes-o.real" 646652
637 /usr/src/games/fortune/datfiles/murphy "murphy" 60503
635 /usr/src/games/fortune/datfiles/limerick "limerick" 129585
589 /usr/src/crypto/openssl/doc/ssleay.txt "ssleay.txt" 283123
478 /usr/src/contrib/gdb/gdb/symfile.c "symfile.c" 114203
475 /usr/src/games/fortune/datfiles/gerrold.limerick "gerrold.limerick" 25622
384 /usr/src/contrib/tcsh/tc.func.c "tc.func.c" 49474
323 /usr/src/contrib/file/magic.mime "magic.mime" 33539
318 /usr/src/sys/dev/ed/if_ed_3c503.c "if_ed_3c503.c" 9433
310 /usr/src/crypto/openssl/ssl/s2_enc.c "s2_enc.c" 6224
237 /usr/src/crypto/openssl/crypto/objects/objects.txt "objects.txt" 35766
.
[root@ ~]#
[root@ ~]#

Η αναζήτηση πήρε περίπου 0.065 δευτερόλεπτα. Καθόλου άσχημα.

Το swish-e μας ενημερώνει τον βαθμό κατάταξης (ranking) του κάθε αρχείου το οποίο περιέχει τον όρο αναζήτησης, την τοποθεσία και το όνομα του, και το μέγεθος του. Η μορφή εξόδου μπορεί να διαμορφωθεί από τον χρήστη, είτε μέσω του configuration file, είτε μέσω της επιλογής -x.

Αρχεία με υψηλότερη κατάταξη περιέχουν τον όρο περισσότερες φορές από ότι τα αρχεία με χαμηλότερη κατάταξη.

Φιλτράρισμα Εισόδου

Ωραία. Φαινόταν ότι το swish-e κάνει την δουλειά που ήθελα. Υπήρχε όμως ακόμη ένα σημείο το οποίο ήθελα να ερευνήσω: πολλά από τα αρχεία τα οποία θα πρέπει να γίνουν index θα είναι συμπιεσμένα. Μπορεί το swish-e να χειριστεί συμπιεσμένα αρχεία;

Η απάντηση ήταν ναι! Μέσω του αρχείου ρυθμίσεων, μπορείς να ζητήσεις από το swish-e να περάσει ορισμένα αρχεία εισόδου από κάποια άλλη εφαρμογή (φίλτρο), πριν τύχουν επεξεργασίας από το swish-e. Αυτό επιτυγχάνεται μέσω της ρύθμισης FileFilter.

Στην δική μου περίπτωση, ήξερα ότι κάποια αρχεία θα είναι συμπιεσμένα με bzip2 ή gzip. Για αυτό λοιπόν, πρόσθεσα στο αρχείο ρυθμίσεων τις ακόλουθες δύο γραμμές:

FileFilter .bz2 bzcat '"%p"'
FileFilter .gz  gzcat '"%p"'

Με αυτό τον τρόπο, ζητώ από το swish-e όταν βρει αρχεία με επέκταση .bz2 ή .gz, να τρέξει την εντολή bzcat και gzcat αντίστοιχα, περνώντας το όνομα του αρχείου (αυτό λέει το %p) ως παράμετρο. Το swish-e παίρνει την έξοδο από το τρέξιμο της εντολής (στην περίπτωση μας θα είναι τα περιεχόμενα του αποσυμπιεσμένου αρχείου) και την χρησιμοποιεί για να φτιάξει το index.

Αυτό λοιπόν ήταν το swish-e: ένα ισχυρό εργαλείο δημιουργίας ευρετηρίων αναζήτησης για αρχεία κειμένου, HTML και XML.

Στην δημοσίευση ανέφερα πολύ επιφανειακά κάποια βασικά χαρακτηριστικά του. Για μια πληρέστερη εικόνα, μπορείτε να ανατρέξετε εδώ:

Να αναφέρω επίσης ότι δοκίμασα το σύστημα (μεταγλώττιση, κτίσιμο index και αναζήτηση) στις ακόλουθες πλατφόρμες:

  • FreeBSD 7 — κανένα πρόβλημα
  • OpenBSD 4.4 — κανένα πρόβλημα
  • Red Hat Enterprise Linux 4 Update 4 — κανένα πρόβλημα
  • Cygwin — τα filters δεν φαίνεται να δουλεύουν

Ελπίζω να φανεί χρήσιμο και σε μερικούς από εσάς.

*Τα βήματα διαφέρουν από εφαρμογή σε εφαρμογή. Οι ενδιαφερώμενοι θα πρέπει να ανατρέξουν στις οδηγίες μεταγλώττισης του εκάστοτε πακέτου, οι οποίες συνήθως παρέχονται μαζί με τον κώδικα.

2 comments

    Reader's Comments

  1. Ευχαριστούμε για την πολύ χρήσιμη ενημέρωση! Ίσως κάποτε το χρειαστώ αυτό το εργαλείο. :)

    -- Γιώργος Μιχαήλ ~xeirwn, June 14, 2009

  2. χρήσιμο, ευχαριστούμε!

    -- Ελένη Γεωργίου ~geleni, June 15, 2009

Nearby

« newer | up | older »


Copyright © 2000-2010 phigita. All rights reserved.
Powered by the blood, sweat, and tears of the phigita.net community.