Hvorfor trengs Lucene?
Søk er en av de vanligste operasjonene vi utfører flere ganger om dagen. Dette søket kan være på tvers av flere websider som finnes på nettet eller et musikkprogram eller et kodelager eller en kombinasjon av alle disse. Man kan tro at en enkel relasjonsdatabase også kan støtte søk. Dette er riktig. Databaser som MySQL støtter fulltekstsøk. Men hva med Internett eller et musikkprogram eller et kodelager eller en kombinasjon av alle disse? Databasen kan ikke lagre disse dataene i kolonnene. Selv om det gjorde det, vil det ta uakseptabel tid å kjøre søket så stort.
En søkemotor med fulltekst kan kjøre et søk på millioner av filer samtidig. Hastigheten som data lagres i en applikasjon i dag er enorm. Å kjøre fulltekstsøk på denne typen datavolum er en vanskelig oppgave. Dette er fordi informasjonen vi trenger kan eksistere i en enkelt fil av milliarder filer som holdes på nettet.
Hvordan Lucene fungerer?
Det åpenbare spørsmålet som du bør tenke på er hvordan Lucene er så rask i å kjøre fulltekstsøk? Svaret på dette er selvfølgelig ved hjelp av indekser det skaper. Men i stedet for å lage en klassisk indeks, bruker Lucene Inverterte indekser.
I en klassisk indeks samler vi for hvert dokument hele listen over ord eller termer dokumentet inneholder. I en omvendt indeks lagrer vi for hvert ord i alle dokumentene hvilket dokument og posisjon som dette ordet / begrepet kan bli funnet på. Dette er en høy standard algoritme som gjør søket veldig enkelt. Tenk på følgende eksempel for å lage en klassisk indeks:
Doc1 -> "This", "is", "simple", "Lucene", "sample", "classic", "inverted", "index"Doc2 -> "Running", "Elasticsearch", "Ubuntu", "Update"
Doc3 -> "RabbitMQ", "Lucene", "Kafka", "", "Spring", "Boot"
Hvis vi bruker omvendt indeks, vil vi ha indekser som:
Dette -> (2, 71)Lucene -> (1, 9), (12,87)
Apache -> (12, 91)
Framework -> (32, 11)
Inverterte indekser er mye lettere å vedlikeholde. Anta at hvis vi ønsker å finne Apache i mine vilkår, vil jeg ha svar med en gang med inverterte indekser mens klassisk søk vil kjøre på komplette dokumenter som kanskje ikke har vært mulig å kjøre i sanntidsscenarier.
Lucene arbeidsflyt
Før Lucene faktisk kan søke i dataene, må den utføre trinn. La oss visualisere disse trinnene for bedre forståelse:
Lucene arbeidsflyt
Som vist i diagrammet, er det dette som skjer i Lucene:
- Lucene får dokumentene og andre datakilder
- For hvert dokument konverterer Lucene først disse dataene til ren tekst, og deretter konverterer analysatorene denne kilden til ren tekst
- For hver periode i ren tekst opprettes de omvendte indeksene
- Indeksene er klare til å bli søkt
Med denne arbeidsflyten er Lucene en veldig sterk søkemotor i fulltekst. Men dette er den eneste delen Lucene oppfyller. Vi må utføre arbeidet selv. La oss se på komponentene i indeksering som trengs.
Lucene Components
I denne delen vil vi beskrive de grunnleggende komponentene og de grunnleggende Lucene-klassene som brukes til å lage indekser:
- Kataloger: En Lucene-indeks lagrer data i normale filsystemregistreringer eller i minne hvis du trenger mer ytelse. Det er helt appens valg å lagre data hvor som helst, en database, RAM eller disken.
- Dokumenter: Dataene vi leverer til Lucene-motoren må konverteres til ren tekst. For å gjøre dette lager vi et dokumentobjekt som representerer den datakilden. Senere, når vi kjører et søk, som et resultat, vil vi få en liste over dokumentobjekter som tilfredsstiller spørringen vi passerte.
- Enger: Dokumentene er fylt med en samling felt. Et felt er rett og slett et par (navn, verdi) gjenstander. Så mens vi oppretter et nytt dokumentobjekt, må vi fylle det med den slags parede data. Når et felt er indeksert omvendt, blir verdien av feltet tokenisert og er tilgjengelig for søk. Nå, mens vi bruker Fields, er det ikke viktig å lagre det faktiske paret, men bare den inverterte indekserte. På denne måten kan vi bestemme hvilke data som bare er søkbare og ikke viktig å lagre. La oss se på et eksempel her:
Feltindeksering
I tabellen ovenfor bestemte vi oss for å lagre noen felt, og andre er ikke lagret. Kroppsfeltet er ikke lagret, men indeksert. Dette betyr at e-posten vil bli returnert som et resultat når spørringen om en av vilkårene for kroppsinnholdet kjøres.
- Vilkår: Vilkår representerer et ord fra teksten. Begreper er hentet fra analyse og tokenisering av Fields 'verdier, altså Term er den minste enheten som søket kjøres på.
- Analysatorer: En analysator er den mest avgjørende delen av indekserings- og søkeprosessen. Det er analysatoren som overfører vanlig tekst til poletter og vilkår slik at de kan søkes. Vel, det er ikke det eneste ansvaret til en analysator. En analysator bruker en Tokenizer for å lage tokens. En analysator gjør også følgende oppgaver:
- Stemming: En analysator konverterer ordet til en stamme. Dette betyr at 'blomster' konverteres til stammeordet 'blomst'. Så når et søk etter 'blomst' blir kjørt, returneres dokumentet.
- Filtrering: En analysator filtrerer også stoppordene som 'The', 'is' osv. ettersom disse ordene ikke tiltrekker seg spørsmål som skal kjøres og ikke er produktive.
- Normalisering: Denne prosessen fjerner aksenter og andre tegnmarkeringer.
Dette er bare det vanlige ansvaret til StandardAnalyzer.
Eksempel på applikasjon
Vi bruker en av de mange Maven-arketypene til å lage et eksempel på et eksempel. For å opprette prosjektet, kjør følgende kommando i en katalog som du vil bruke som arbeidsområde:
mvn arketype: generer -DroupId = com.linuxhint.eksempel -DartifactId = LH-LuceneExample -DarchetypeArtifactId = maven-archetype-quickstart -DinteractiveMode = falseHvis du kjører maven for første gang, vil det ta noen sekunder å fullføre genereringskommandoen fordi maven må laste ned alle nødvendige plugins og gjenstander for å gjøre generasjonsoppgaven. Slik ser prosjektutgangen ut:
Prosjektoppsett
Når du har opprettet prosjektet, kan du åpne det i din favoritt IDE. Neste trinn er å legge til passende Maven-avhengigheter i prosjektet. Her er pom.xml-fil med passende avhengigheter:
Til slutt, for å forstå alle JAR-ene som legges til i prosjektet når vi la til denne avhengigheten, kan vi kjøre en enkel Maven-kommando som lar oss se et komplett avhengighetstre for et prosjekt når vi legger til noen avhengigheter til det. Her er en kommando som vi kan bruke:
mvn avhengighet: treNår vi kjører denne kommandoen, vil den vise oss følgende avhengighetstre:
Til slutt oppretter vi en SimpleIndexer-klasse som kjører
importere java.io.Fil;
importere java.io.FileReader;
importere java.io.IO Unntak;
importere organisasjon.apache.lucene.analyse.Analysator;
importere organisasjon.apache.lucene.analyse.standard.Standardanalysator;
importere organisasjon.apache.lucene.dokument.Dokument;
importer org.apache.lucene.dokument.StoredField;
importere organisasjon.apache.lucene.dokument.Tekstfelt;
importere organisasjon.apache.lucene.indeks.IndexWriter;
importer org.apache.lucene.indeks.IndexWriterConfig;
importere organisasjon.apache.lucene.butikk.FSDirectory;
importer org.apache.lucene.util.Versjon;
offentlig klasse SimpleIndexer
private static final String indexDirectory = "/ Brukere / shubham / et sted / LH-Lucene Eksempel / Indeks";
privat statisk slutt String dirToBeIndexed = "/ Brukere / shubham / et sted / LH-Lucene Eksempel / src / main / java / com / linuxhint / eksempel";
offentlig statisk ugyldig hoved (String [] args) kaster Unntak
File indexDir = new File (indexDirectory);
File dataDir = ny fil (dirToBeIndexed);
SimpleIndexer indekser = ny SimpleIndexer ();
int numIndexed = indekser.indeks (indexDir, dataDir);
System.ute.println ("Totalt antall filer indeksert" + numIndexed);
private int-indeks (File indexDir, File dataDir) kaster IOException
Analysatoranalysator = ny StandardAnalyzer (versjon.LUCENE_46);
IndexWriterConfig config = ny IndexWriterConfig (versjon.LUCENE_46,
analysator);
IndexWriter indexWriter = ny IndexWriter (FSDirectory.åpen (indexDir),
config);
Fil [] filer = dataDir.listFiles ();
for (Fil f: filer)
System.ute.println ("Indekseringsfil" + f.getCanonicalPath ());
Dokumentdok = nytt Dokument ();
dok.legg til (nytt TextField ("innhold", ny FileReader (f)));
dok.legg til (ny StoredField ("filnavn", f.getCanonicalPath ()));
indexWriter.addDocument (doc);
int numIndexed = indexWriter.maxDoc ();
indexWriter.Lukk();
return numIndexed;
I denne koden laget vi nettopp en dokumentforekomst og la til et nytt felt som representerer filinnholdet. Her er utdataene vi får når vi kjører denne filen:
Indekseringsfil / Brukere / shubham / et sted / LH-Lucene Eksempel / src / main / java / com / linuxhint / eksempel / SimpleIndexer.javaTotalt antall indekserte filer 1
Det opprettes også en ny katalog i prosjektet med følgende innhold:
Indeksdata
Vi vil analysere hva alle filer er opprettet i denne indeksen i flere leksjoner som kommer på Lucene.
Konklusjon
I denne leksjonen så vi på hvordan Apache Lucene fungerer, og vi laget også et enkelt eksempelprogram som var basert på Maven og java.