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://localhost:5984/dbname/_fti/_design/test/by_title?q=nadpis
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://localhost:5984/dbname/_fti/_design/test/by_title?q=title:nadp*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.
Nad lucene existuje nastroj elasticsearch, ktery by stalo za to zminit jako alternativu:
http://www.elasticsearch.org/
V clanku je to spomenute hned hore
„Riešení sa ponúka hneď niekoľko. S pomedzi mnohých môžme použiť napríklad Elasticsearch alebo Lucene.“