Fulltext vyhľadávanie v CouchDB

O CouchDB bolo už na Zdrojáku napísaných množstvo článkov. Od miniseriálu Jakuba Kulhana až po preklad kompletného sprievodcu CouchDB od Martina Malého. Dnes si ukážeme základné možnosti fulltextového vyhľadávania s nástrojom Lucene v tejto čoraz populárnejšej databáze.

Na úvod krátke predstavenie, pre tých čo sa s CouchDB doteraz nestretli. CouchDB je dokumentovo orientovaná databáza s „iným“ prístupom k ukladaniu údajov. Umožňuje nám okrem iného vytvárať rôzne pohľady „views“ cez javascriptové map-reduce funkcie. Tieto funkcie nám úplne postačujú na vytvorenie napríklad stromovej štruktúry a jednoduchého zatrieďovania a získavania dát. Čo v prípade, že máme napríklad vlastný blog a chceme umožniť návštevníkom, aby mohli fulltextovo vyhľadávať v publikovaných článkoch? Riešení sa ponúka hneď niekoľko. S pomedzi mnohých môžme použiť napríklad Elasticsearch alebo Lucene.

Lucene

V tomto článku sa budeme venovať systému Lucene. Je to open source projekt zastrešený Apache Software Foundation. Kompletne napísaný v JAVE (na svoje fungovaniu vyžaduje nainštalované JRE) a je určený na fulltextové vyhľadávanie. Poskytuje možnosť škálovania a bez problémov spolupracuje s CouchDB. Je nenáročný na konfiguráciu, inštaláciu, a ako sa ochvíľu presvedčíme, aj na používanie.

Inštalácia Lucene

Jednoduchý návod na inštaláciu pre Ubuntu najdete tu.

Je v ňom však jeden preklep, a to v bode 11. Namiesto

apt-get install get-core maven2

použite

apt-get install git-core maven2

Pre ďaľšie distribúcie sú návody viac či menej rovnaké.

Configurácia CouchDB

Nakonfigurujeme rozhranie pre komunikáciu z couchdb-lucene  v CouchDB local.ini

Verzia CouchDB  < 1.1

[couchdb]
os_process_timeout=60000 ; // zvýšime čas pre vrátenie výsledku z CouchDB, je to dôležité ak nám vyhľadávanie trvá dlhšie

[external]
fti=/path/to/python /path/to/couchdb-lucene/tools/couchdb-external-hook.py // nastavíme cestu pre externé volanie lucene

[httpd_db_handlers]
_fti = {couch_httpd_external, handle_external_req, <<"fti">>} // zaregistrujeme http handler

Verzia CoucDB 1.1 +

Nová verzia  databázy už nepotrebuje toľko nastavovaní, úplne stačí iba registrácia http handlera z url na lucene.

[httpd_global_handlers]
_fti = {couch_httpd_proxy, handle_proxy_req, <<"http://127.0.0.1:5985">>}

Pripravíme si testovacie dáta

Najskôr do databázy vložíme testovacie dáta, v ktorých chceme umožniť vyhľadávanie. Napríklad články z nášho blogu obsahujúce nadpis, perex a obsah. Príklad:

{
    "type": "article",
    "title": "Nadpis článku",
    "perex": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus nec.",
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas eu turpis metus, vel hendrerit ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla magna arcu, pharetra id gravida quis, fermentum convallis nisi. Nullam felis velit, rutrum nec aliquet et, viverra sed ante. Proin iaculis neque a enim interdum pharetra. Pellentesque eu euismod libero. Fusce tristique vehicula justo vel euismod. Vestibulum nec nisi sem, at faucibus quam. Aliquam quis ante metus."
}

Nastavenie indexovania

Vytvoríme si design dokument, v ktorom nastavíme parametre indexácie vyhľadávania. Každý dokument môže obsahovať neobmedzené množstvo indexov. Pre náš príklad si pripravíme dva. Prvý pre vyhľadávanie iba v nadpise článku, druhý pre vyhľadávanie vo všetkých položkách jednotlivých článkov.

{
    "_id":"_design/test",
    "fulltext":{
        "by_title":{
            "index":"function(doc){
                if(doc.type == 'article') // indexujeme len články
                  {
                     var ret = new Document();
                     ret.add(doc.title); // zaindexujeme položku title
                     return ret;
                  }
                  else
                  {
                     return null;
                  }
             }"
        },

        "by_article":{
            "index":"function(doc){
                if(doc.type == 'article') // indexujeme len články
                   {
                      var ret = new Document();
                      // pridáme všetky položky, v ktorých chceme vyhľadávať
                      ret.add(doc.title);
                      ret.add(doc.perex);
                      ret.add(doc.content);
                      return ret;
                    }
                    else
                    {
                      return null;
                    }
              }"
          }
    }
}

Vyhľadávanie

Môžeme sa pustiť do samotného vyhľadávania. Najprv skúsime vyhľadávať iba v nadpisoch.http://lo­calhost:5984/dbna­me/_fti/_desig­n/test/by_title?q=nad­pis

Odpoveďou na našu požiadavku je klasický JSON objekt, obsahujúci počet nájdených dokumentov, čas vyhľadávania a  zoznam „_ID“ nájdených dokumentov.

{
    "q": "nadpis",
    "skip": 0, // určuje koľko dokumentov bolo preskočených, url: &skip=
    "limit": 10, // url: &limit=
    "total_rows": 1,
    "fetch_duration", 1,
    "rows":[
        {
            "id":'article-1',
            "score": 1.82347
        }
     ]
}

Toto riešenie je nedostatočné; nakoľko na to, aby sme získali kompletný obsah vyhľadaných dokumentov, je nutné vykonať ďaľšiu GET požiadavku na samotný dokument. Pridaním parametra &include_docs do GETu docielime vrátenie okrem „_ID“ aj kompletného dokumentu uloženého v CouchDB. Výsledok:

"rows":[
        {
            "id":'article-1',
            "doc":
               {
                  "title":"Nadpis članku".....
                  // celý dokument
               }
            "score": 1.82347
         }
]

Tu však môže nastať ďaľšia situácia: ak by bol dokument (článok) veľký a my chceme zobrazovať iba určité dáta, napríklad do zoznamu vyhľadaných položiek alebo do suggestu, je zbytočné ťahať z DB celý dokument. Vrátime sa k indexom a jeden si upravíme

"by_title":{
    "index":"function(doc){
            if(doc.type == 'article') // indexujeme len články
               {
                   var ret = new Document();
                   ret.add(doc.title, {'field':'title', 'store':'yes'});
                   // zaindexujeme položku title a zároveň ju uložíme do lucene
                   return ret;
               }
               else
               {
                   return null;
               }
           }"
}

Požiadavku na vyhľadávanie upravíme: http://localhos­t:5984/dbname/_fti/_de­sign/test/by_ti­tle?q=title:nad­p*Vo výsledku dostaneme požadované dáta na zobrazenie nadpisov článkov bez prenosu celého dokumentu z DB.

Lucene poskytuje veľké množstvo nastavení a parametrov, ktoré je možné použiť pre indexáciu a získavanie dát. V tejto časti sme si ukázali základné možnosti fulltextového vyhľadávania pre CouchDB. Nabudúce si ukážeme vyhľadávanie v prílohách, či v našich zemepisných šírkach dôležitú možnosť vyhľadávať s diakritikou a bez nej.

Michal (Balvan) Bartha je nadšený programátor. Baví ho vyhľadávanie nových technológií a ich aplikácia na reálne problémy. Viac na LinkedIn

Zdroj: https://www.zdrojak.cz/?p=3573