Hvorfor er der brug for Lucene?
Søgning er en af de mest almindelige operationer, vi udfører flere gange om dagen. Denne søgning kan være på tværs af flere websider, der findes på Internettet eller et musikapplikation eller et kodelager eller en kombination af alle disse. Man tror måske, at en simpel relationsdatabase også kan understøtte søgning. Det er rigtigt. Databaser som MySQL understøtter søgning i fuld tekst. Men hvad med internettet eller et musikprogram eller et kodelager eller en kombination af alle disse? Databasen kan ikke gemme disse data i sine kolonner. Selvom det gjorde det, vil det tage en uacceptabel tid at køre søgningen så stort.
En søgemaskine i fuld tekst er i stand til at køre en søgeforespørgsel på millioner af filer på én gang. Den hastighed, hvormed data lagres i en applikation i dag, er enorm. At køre fuldtekstsøgning på denne type datamængde er en vanskelig opgave. Dette skyldes, at de oplysninger, vi har brug for, muligvis findes i en enkelt fil ud af milliarder af filer, der er gemt på nettet.
Hvordan Lucene fungerer?
Det åbenlyse spørgsmål, som du skal tænke på, er, hvordan er Lucene så hurtig til at køre fuldtekst-søgeforespørgsler? Svaret på dette er naturligvis ved hjælp af indekser, det skaber. Men i stedet for at oprette et klassisk indeks bruger Lucene det Omvendte indekser.
I et klassisk indeks samler vi for hvert dokument den fulde liste over ord eller udtryk, dokumentet indeholder. I et omvendt indeks gemmer vi for hvert ord i alle dokumenter hvilket dokument og position dette ord / udtryk kan findes på. Dette er en høj standard algoritme, der gør søgningen meget let. Overvej følgende eksempel på oprettelse af et klassisk indeks:
Doc1 -> "Dette", "er", "simpelt", "Lucene", "prøve", "klassisk", "omvendt", "indeks"Doc2 -> "Running", "Elasticsearch", "Ubuntu", "Update"
Doc3 -> "RabbitMQ", "Lucene", "Kafka", "", "Spring", "Boot"
Hvis vi bruger inverteret indeks, har vi indeks som:
Dette -> (2, 71)Lucene -> (1, 9), (12,87)
Apache -> (12, 91)
Framework -> (32, 11)
Inverterede indekser er meget lettere at vedligeholde. Antag, at hvis vi vil finde Apache i mine vilkår, har jeg straks svar med inverterede indekser, mens klassisk søgning vil køre på komplette dokumenter, som måske ikke har været muligt at køre i realtidsscenarier.
Lucene-arbejdsgang
Før Lucene rent faktisk kan søge i dataene, skal den udføre trin. Lad os visualisere disse trin for en bedre forståelse:
Lucene Workflow
Som vist i diagrammet er dette, hvad der sker i Lucene:
- Lucene får dokumenterne og andre datakilder
- For hvert dokument konverterer Lucene først disse data til almindelig tekst, og derefter konverterer analysatorerne denne kilde til almindelig tekst
- For hvert udtryk i almindelig tekst oprettes de omvendte indekser
- Indekserne er klar til at blive søgt
Med denne arbejdsgang er Lucene en meget stærk søgemaskine i fuldtekst. Men dette er den eneste del, Lucene opfylder. Vi er nødt til at udføre arbejdet selv. Lad os se på de komponenter, der er nødvendige for indeksering.
Lucene-komponenter
I dette afsnit beskriver vi de grundlæggende komponenter og de grundlæggende Lucene-klasser, der bruges til at oprette indekser:
- Kataloger: Et Lucene-indeks gemmer data i normale filsystemdirektiv eller i hukommelsen, hvis du har brug for mere ydeevne. Det er helt apps valg at gemme data, hvor det vil, en database, RAM eller disken.
- Dokumenter: De data, vi leverer til Lucene-motoren, skal konverteres til almindelig tekst. For at gøre dette opretter vi et dokumentobjekt, der repræsenterer den datakilde. Senere, når vi kører en søgeforespørgsel, som et resultat, får vi en liste over dokumentobjekter, der tilfredsstiller den forespørgsel, vi har bestået.
- Felter: Dokumenter er udfyldt med en samling felter. Et felt er simpelthen et par (navn, værdi) genstande. Så mens vi opretter et nyt dokumentobjekt, skal vi udfylde det med den slags parrede data. Når et felt er omvendt indekseret, markeres feltets værdi og er tilgængelig til søgning. Nu, mens vi bruger felter, er det ikke vigtigt at gemme det faktiske par, men kun det omvendte indekseret. På denne måde kan vi beslutte, hvilke data der kun kan søges og ikke er vigtige for at blive gemt. Lad os se på et eksempel her:
Feltindeksering
I ovenstående tabel besluttede vi at gemme nogle felter, og andre er ikke gemt. Kroppefeltet er ikke gemt, men indekseret. Dette betyder, at e-mailen returneres som et resultat, når forespørgslen om et af vilkårene for body-indhold køres.
- Vilkår: Vilkår repræsenterer et ord fra teksten. Vilkår udvindes således fra analysen og tokeniseringen af Fields 'værdier Term er den mindste enhed, som søgningen køres på.
- Analysatorer: En analysator er den mest afgørende del af indekserings- og søgningsprocessen. Det er analysatoren, der overfører almindelig tekst til tokens og vilkår, så de kan søges. Nå, det er ikke det eneste ansvar, som en analysator har. En analysator bruger en Tokenizer til at fremstille tokens. En analysator udfører også følgende opgaver:
- Stemming: En analysator konverterer ordet til en stamme. Dette betyder, at 'blomster' konverteres til stammeordet 'blomst'. Så når en søgning efter 'blomst' køres, returneres dokumentet.
- Filtrering: En analysator filtrerer også stopordene som 'The', 'is' osv. da disse ord ikke tiltrækker nogen forespørgsler, der skal køres og ikke er produktive.
- Normalisering: Denne proces fjerner accenter og andre tegnmarkeringer.
Dette er bare det normale ansvar for StandardAnalyzer.
Eksempel på anvendelse
Vi bruger en af de mange Maven-arketyper til at oprette et prøveprojekt til vores eksempel. For at oprette projektet skal du udføre følgende kommando i en mappe, som du vil bruge som arbejdsområde:
mvn arketype: generer -DroupId = com.linuxhint.eksempel -DartifactId = LH-Lucene Eksempel -DarchetypeArtifactId = maven-archetype-quickstart -DinteractiveMode = falseHvis du kører maven for første gang, vil det tage et par sekunder at udføre genereringskommandoen, fordi maven er nødt til at downloade alle de nødvendige plugins og artefakter for at gøre genereringsopgaven. Sådan ser projektudgangen ud:
Projektopsætning
Når du har oprettet projektet, er du velkommen til at åbne det i din foretrukne IDE. Næste trin er at tilføje passende Maven-afhængigheder til projektet. Her er pom.xml-fil med de relevante afhængigheder:
Endelig, for at forstå alle de JAR, der føjes til projektet, når vi tilføjede denne afhængighed, kan vi køre en simpel Maven-kommando, der giver os mulighed for at se et komplet afhængighedstræ for et projekt, når vi tilføjer nogle afhængigheder til det. Her er en kommando, som vi kan bruge:
mvn afhængighed: træNår vi kører denne kommando, viser den os følgende afhængighedstræ:
Endelig opretter vi en SimpleIndexer-klasse, der kører
importer java.io.Fil;
importer java.io.FileReader;
importer java.io.IOUndtagelse;
importorg.apache.lucene.analyse.Analysator;
importorg.apache.lucene.analyse.standard.Standardanalysator;
importorg.apache.lucene.dokument.Dokument;
importorg.apache.lucene.dokument.Opbevaret felt;
importorg.apache.lucene.dokument.Tekstfelt;
importorg.apache.lucene.indeks.IndexWriter;
importorg.apache.lucene.indeks.IndexWriterConfig;
importorg.apache.lucene.butik.FSDirectory;
importorg.apache.lucene.util.Version;
offentlig klasse SimpleIndexer
privat statisk endelig String indexDirectory = "/ Brugere / shubham / et sted / LH-Lucene Eksempel / Indeks";
privat statisk endelig String dirToBeIndexed = "/ Brugere / shubham / et eller andet sted / LH-LuceneExample / src / main / java / com / linuxhint / eksempel";
offentlig statisk ugyldigt hoved (String [] args) kaster Undtagelse
File indexDir = ny fil (indexDirectory);
File dataDir = ny fil (dirToBeIndexed);
SimpleIndexer indexer = ny SimpleIndexer ();
int numIndexed = indekser.indeks (indexDir, dataDir);
System.ud.println ("Samlet antal filer indekseret" + numIndexed);
privat int-indeks (File indexDir, File dataDir) kaster IOException
Analysatoranalysator = ny StandardAnalyzer (version.LUCENE_46);
IndexWriterConfig config = ny IndexWriterConfig (version.LUCENE_46,
analysator);
IndexWriter indexWriter = ny IndexWriter (FSDirectory.åben (indexDir),
config);
Fil [] filer = dataDir.listFiles ();
for (Fil f: filer)
System.ud.println ("Indekseringsfil" + f.getCanonicalPath ());
Dokument doc = nyt dokument ();
dok.tilføj (nyt TextField ("indhold", ny FileReader (f)));
dok.tilføj (nyt StoredField ("filnavn", f.getCanonicalPath ()));
indexWriter.addDocument (doc);
int numIndexed = indexWriter.maxDoc ();
indexWriter.tæt();
return numIndexed;
I denne kode oprettede vi netop en dokumentinstans og tilføjede et nyt felt, der repræsenterer filindholdet. Her er det output, vi får, når vi kører denne fil:
Indekseringsfil / Brugere / shubham / et eller andet sted / LH-Lucene Eksempel / src / main / java / com / linuxhint / eksempel / SimpleIndexer.javaI alt indekserede filer 1
Der oprettes også en ny mappe inde i projektet med følgende indhold:
Indeksdata
Vi analyserer, hvad alle filer oprettes i dette indeks i flere lektioner, der kommer på Lucene.
Konklusion
I denne lektion kiggede vi på, hvordan Apache Lucene fungerer, og vi lavede også et simpelt eksempelapplikation, der var baseret på Maven og java.