Bevezetés az Apache Lucene-be

1. Áttekintés

Az Apache Lucene egy teljes szövegű keresőmotor, amely különböző programozási nyelvekről használható.

Ebben a cikkben megpróbáljuk megérteni a könyvtár alapfogalmait és létrehozni egy egyszerű alkalmazást.

2. Maven Setup

A kezdéshez először adjunk hozzá szükséges függőségeket:

 org.apache.lucene lucene-core 7.1.0 

A legújabb verzió itt található.

A keresési lekérdezések elemzéséhez a következőkre is szükségünk lesz:

 org.apache.lucene lucene-queryparser 7.1.0 

Itt tekintheti meg a legújabb verziót.

3. Alapfogalmak

3.1. Indexelés

Egyszerűen fogalmazva, a Lucene az adatok „fordított indexelését” használja - az oldalak kulcsszavakhoz való hozzárendelése helyett a kulcsszavakat oldalakhoz térképezi fel akárcsak egy szójegyzék minden könyv végén.

Ez gyorsabb keresési válaszokat tesz lehetővé, mivel az indexen keresztül keres, ahelyett, hogy közvetlenül a szövegben keresne.

3.2. Dokumentumok

Itt egy dokumentum mezők gyűjteménye, és minden mezőhöz tartozik egy érték.

Az indexek általában egy vagy több dokumentumból állnak, a keresési eredmények pedig a legjobban illeszkedő dokumentumok halmazai.

Nem mindig egyszerű szöveges dokumentum, lehet adatbázis tábla vagy gyűjtemény is.

3.3. Mezők

A dokumentumok mezőadatokkal rendelkezhetnek, ahol a mező tipikusan egy adatértéket tartalmazó kulcs:

cím: A tea testének jósága: A gyógyteás ital jóságának megvitatása ...

Figyelje meg itt cím és test mezők, és együtt vagy külön is kereshetők.

3.4. Elemzés

Egy elemzés az adott szöveget kisebb és pontos egységekké konvertálja a keresés megkönnyítése érdekében.

A szöveg különféle műveleteken megy keresztül a kulcsszavak kinyerésén, a gyakori szavak és írásjelek eltávolításán, a szavak kisbetűvé változtatásán stb.

Erre a célra több beépített analizátor létezik:

  1. StandardAnalyzer - elemzés az alapnyelvtan alapján, eltávolítja a leállítási szavakat, például „a”, „an” stb.
  2. SimpleAnalyzer - betű nélküli karakter alapján megtöri a szöveget, és kisbetűvé konvertálja
  3. WhiteSpaceAnalyzer - megtöri a szöveget a szóközök alapján

További elemzők állnak rendelkezésre számunkra, hogy felhasználhassuk és testre szabhassuk.

3.5. Keresés

Az index felépítése után az a segítségével kereshetünk az indexben Lekérdezés és egy IndexSearcher. A keresési eredmény általában egy eredményhalmaz, amely tartalmazza a visszakeresett adatokat.

Vegye figyelembe, hogy egy IndexWritter felelős az index és egy IndexSearcher az index kereséséhez.

3.6. Lekérdezés szintaxisa

A Lucene nagyon dinamikus és könnyen írható lekérdezési szintaxist biztosít.

Szabad szöveg keresésére csak egy szöveget használunk Húr mint a lekérdezés.

Szöveg kereséséhez egy adott mezőben a következőket használjuk:

mezőNév: szöveg pl .: cím: tea

Tartomány keresés:

időbélyeg: [1509909322,1572981321] 

Helyettesítő karakterekkel is kereshetünk:

ital

egyetlen karaktert keresne a helyettesítő karakter helyett?

d * k

„d” betűvel kezdődő és „k” betűvel végződő szavakra keres, amelyek között több karakter van.

uni *

megtalálja az „uni” kezdetű szavakat.

Kombinálhatjuk ezeket a lekérdezéseket, és összetettebb lekérdezéseket hozhatunk létre. És tartalmazzon olyan logikai operátort, mint az AND, NOT, OR:

cím: "Tea a reggeliben" ÉS "kávé"

További információ a lekérdezés szintaxisáról itt.

4. Egyszerű alkalmazás

Hozzunk létre egy egyszerű alkalmazást, és indexeljünk néhány dokumentumot.

Először létrehozunk egy memóriában lévő indexet, és hozzáadunk néhány dokumentumot:

... Directory memoryIndex = new RAMDirectory (); StandardAnalyzer analizátor = new StandardAnalyzer (); IndexWriterConfig indexWriterConfig = új IndexWriterConfig (elemző); IndexWriter író = új IndexWriter (memoryIndex, indexWriterConfig); Dokumentumdokumentum = új Dokumentum (); document.add (új TextField ("cím", cím, Field.Store.YES)); document.add (new TextField ("body", body, Field.Store.YES)); writter.addDocument (dokumentum); író.zár (); 

Itt létrehozunk egy dokumentumot a TextField és adja hozzá őket az indexhez a IndexWriter. A harmadik érv a TextField A konstruktor jelzi, hogy a mező értékét is tárolni kell-e vagy sem.

Az elemzőket az adatok vagy a szöveg darabokra osztására használják, majd kiszűrik belőlük a leállítási szavakat. A stop szavak olyan szavak, mint „a”, „vagyok”, „van” stb. Ezek teljesen függenek az adott nyelvtől.

Ezután hozzunk létre egy keresési lekérdezést, és keressük meg a hozzáadott dokumentum indexét:

public List searchIndex (String inField, String queryString) {Lekérdezés lekérdezése = new QueryParser (inField, analizátor) .parse (queryString); IndexReader indexReader = DirectoryReader.open (memoryIndex); IndexSearcher kereső = new IndexSearcher (indexReader); TopDocs topDocs = kereső.keresés (lekérdezés, 10); Dokumentumlista = new ArrayList (); for (ScoreDoc scoreDoc: topDocs.scoreDocs) {documents.add (kereső.doc (scoreDoc.doc)); } visszaküldési dokumentumok; }

Ban,-ben keresés() metódus, a második egész argumentum azt jelzi, hogy hány felső keresési eredménynek kell visszatérnie.

Most teszteljük:

@Test public void givenSearchQueryWhenFetchedDocumentThenCorrect () {InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex (új RAMDirectory (), új StandardAnalyzer ()); inMemoryLuceneIndex.indexDocument ("Hello world", "Some hello world"); Listázza a dokumentumokat = inMemoryLuceneIndex.searchIndex ("body", "world"); assertEquals ("Hello world", documents.get (0) .get ("title")); }

Itt egy egyszerű dokumentumot adunk az indexhez, két mezővel: „title” és „body”, majd megpróbálunk ugyanabban keresni egy keresési lekérdezés segítségével.

6. Lucene lekérdezések

Mivel most már jól érezzük magunkat az indexelés és a keresés alapjaiban, ássunk egy kicsit mélyebbre.

Korábbi szakaszokban láthattuk az alapvető lekérdezési szintaxist, és annak átalakítását a-vá Lekérdezés például a QueryParser.

A Lucene különféle konkrét megvalósításokat is biztosít:

6.1. TermQuery

A Term a keresés alapegysége, amely tartalmazza a mező nevét és a keresendő szöveget.

TermQuery a legegyszerűbb egyetlen kifejezésből álló lekérdezés:

@Test public void givenTermQueryWhenFetchedDocumentThenCorrect () {InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex (új RAMDirectory (), új StandardAnalyzer ()); inMemoryLuceneIndex.indexDocument ("tevékenység", "nyomon fut"); inMemoryLuceneIndex.indexDocument ("tevékenység", "Az autók úton vannak"); Term kifejezés = új kifejezés ("test", "fut"); Lekérdezés = új TermQuery (kifejezés); Listázza a dokumentumokat = inMemoryLuceneIndex.searchIndex (lekérdezés); assertEquals (2, dokumentumok.méret ()); }

6.2. PrefixQuery

Dokumentum keresése „kezdőbetűvel” szóval:

@Test public void givenPrefixQueryWhenFetchedDocumentThenCorrect () {InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex (új RAMDirectory (), új StandardAnalyzer ()); inMemoryLuceneIndex.indexDocument ("cikk", "Lucene bevezetés"); inMemoryLuceneIndex.indexDocument ("cikk", "Bevezetés a Lucene-be"); Term kifejezés = új kifejezés ("body", "intro"); Lekérdezés = new PrefixQuery (kifejezés); Dokumentumok felsorolása = inMemoryLuceneIndex.searchIndex (lekérdezés); assertEquals (2, dokumentumok.méret ()); }

6.3. WildcardQuery

Ahogy a neve is sugallja, használhatunk helyettesítő karaktereket „*” vagy „?” kereséshez:

// ... Term kifejezés = új kifejezés ("body", "intro *"); Lekérdezés = new WildcardQuery (kifejezés); // ...

6.4. PhraseQuery

A dokumentum szövegsorainak keresésére szolgál:

// ... inMemoryLuceneIndex.indexDocument ("idézetek", "Bármely más nevű rózsa édes illatú lenne."); Lekérdezés = new PhraseQuery (1, "test", új BytesRef ("szag"), új BytesRef ("édes")); Dokumentumok felsorolása = inMemoryLuceneIndex.searchIndex (lekérdezés); // ...

Figyeljük meg, hogy a PhraseQuery konstruktort nevezzük tócsa, amely a szavak közötti távolság az egyeztetendő kifejezések között.

6.5. FuzzyQuery

Ezt akkor használhatjuk, amikor valami hasonló, de nem feltétlenül azonos keresést keresünk:

// ... inMemoryLuceneIndex.indexDocument ("cikk", "Halloween fesztivál"); inMemoryLuceneIndex.indexDocument ("dekoráció", "Halloween-dekorációk"); Term kifejezés = új kifejezés ("test", "hallowen"); Lekérdezés = new FuzzyQuery (kifejezés); Dokumentumok felsorolása = inMemoryLuceneIndex.searchIndex (lekérdezés); // ...

Megpróbáltuk keresni a „Halloween” szöveget, de hibásan írt „hallowen” -nel.

6.6. BooleanQuery

Előfordulhat, hogy összetett kereséseket kell végrehajtanunk, két vagy több különböző típusú lekérdezést kombinálva:

// ... inMemoryLuceneIndex.indexDocument ("Cél", "Las Vegas szingapúri autó"); inMemoryLuceneIndex.indexDocument ("Ingázás Szingapúrban", "Autóbuszok"); Term kifejezés1 = új kifejezés ("test", "szingapúr"); Term kifejezés2 = új kifejezés ("karosszéria", "autó"); TermQuery query1 = új TermQuery (term1); TermQuery query2 = új TermQuery (term2); BooleanQuery booleanQuery = new BooleanQuery.Builder () .add (query1, BooleanClause.Occur.MUST) .add (query2, BooleanClause.Occur.MUST) .build (); // ...

7. A keresési eredmények rendezése

Bizonyos mezők alapján is rendezhetjük a keresési eredményeket tartalmazó dokumentumokat:

@Test public void givenSortFieldWhenSortedThenCorrect () {InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex (új RAMDirectory (), új StandardAnalyzer ()); inMemoryLuceneIndex.indexDocument ("Gangesz", "Indiai folyó"); inMemoryLuceneIndex.indexDocument ("Mekong", "Ez a folyó Dél-Ázsiában folyik"); inMemoryLuceneIndex.indexDocument ("Amazon", "Esőerdő folyó"); inMemoryLuceneIndex.indexDocument ("Rajna", "Európához tartozik"); inMemoryLuceneIndex.indexDocument ("Nílus", "Leghosszabb folyó"); Term kifejezés = új kifejezés ("test", "folyó"); Lekérdezés = new WildcardQuery (kifejezés); SortField sortField = új SortField ("cím", SortField.Type.STRING_VAL, hamis); Rendezés sortByTitle = új Rendezés (sortField); Listázza a dokumentumokat = inMemoryLuceneIndex.searchIndex (lekérdezés, sortByTitle); assertEquals (4, dokumentumok.méret ()); assertEquals ("Amazon", documents.get (0) .getField ("title"). stringValue ()); }

Megpróbáltuk a behúzott dokumentumokat címmezők szerint rendezni, amelyek a folyók neve. A logikai argumentum a SortField konstruktor a rendezési sorrend megfordítására szolgál.

8. Távolítsa el a dokumentumokat az indexből

Próbáljunk meg eltávolítani néhány dokumentumot az indexből egy adott alapján Időtartam:

// ... IndexWriterConfig indexWriterConfig = new IndexWriterConfig (analizátor); IndexWriter író = new IndexWriter (memoryIndex, indexWriterConfig); író.törliDokumentumok (kifejezés); // ...

Ezt teszteljük:

@Test public void whenDocumentDeletedThenCorrect () {InMemoryLuceneIndex inMemoryLuceneIndex = new InMemoryLuceneIndex (új RAMDirectory (), új StandardAnalyzer ()); inMemoryLuceneIndex.indexDocument ("Gangesz", "Indiai folyó"); inMemoryLuceneIndex.indexDocument ("Mekong", "Ez a folyó Dél-Ázsiában folyik"); Term kifejezés = új kifejezés ("cím", "bandák"); inMemoryLuceneIndex.deleteDocument (kifejezés); Lekérdezés = új TermQuery (kifejezés); Dokumentumok felsorolása = inMemoryLuceneIndex.searchIndex (lekérdezés); assertEquals (0, dokumentumok.méret ()); }

9. Következtetés

Ez a cikk gyors bevezetést jelentett az Apache Lucene használatának megkezdéséhez. Ezenkívül különböző lekérdezéseket hajtottunk végre, és rendeztük a visszakeresett dokumentumokat.

Mint mindig, a példák kódja megtalálható a Github oldalon.


$config[zx-auto] not found$config[zx-overlay] not found