Rails tekstinė paieška (Full text search)

Posted by Mindaugas Kurlavičius 04/09/2007 at 22h34

Tekstinė paieška, tai vienas iš svarbiausių reikalavimų beveik visose tinklo aplikacijose. Taigi, apie tai, kaip tekstinę paiešką realizuoti, Rails tinklo aplikacijoje.

Ne paslaptis, kad didžioji žiniatinklių pyrago dalis naudoja MySQL DBVS, taigi ir šiame straipsnyje į tekstinę paiešką pažvelgsime iš MySQL perspektyvos.

Pasižvalgius po interneto platybes, paaiškėjo, kad patys populiariausi tekstinės paieškos realizavimo metodai Rails aplikacijose yra tokie:

  1. MYSQL, LIKE sintaksė.
  2. MYSQL implementuotas teksto indeksavimas.
  3. Acts_as_ferret pluginas.
  4. Acts_as_sphinx pluginas.

MYSQL, LIKE sintaksė

Dar ir iki šiandien plačiai naudojamas dėl paprastumo. Tiesiog į užklausą įterpiame LIKE('%kazkas%') ir gauname norimus rezultatus. Tačiau šio metodo trūkumai - greitis, galimybės (tarkime norime rezultatų 'Bill+Gates-Windows' ir nepatogus naudojimas - Rails nėra pagalbinių metodų LIKE naudojimui, (tarkim norime teksto ieskoti 15-oje modelio atributų, SQL sakinio dalis atrodytų : "attr1 LIKE('%a%') OR attr2 LIKE('%a%') ir.t.t"). Taigi šis principas - tai iš esmės pavyzdys kaip nereikėtų realizuoti tekstinės paieškos žiniatinkliuose :). Nors, žinoma, niekas to nedraudžia daryti esant mažiems poreikiams.

MySQL teksto indeksavimas.

Tai patobulinta MySQL alternatyva LIKE sintaksei. Implementacija paprasta. Kurdami lentelę (MyISAM) tiesiog nurodome FULLTEXT INDEX(name) ir MySQL automatiškai sukurs indeksų lentelę "name" atributui.

CREATE TABLE test (
  id INT(5) PRIMARY KEY NOT NULL AUTO_INCREMENT,
  data TEXT
  FULLTEXT INDEX(data)
);

Paieška:
SELECT * FROM test WHERE MATCH(data) AGAINST('labas')

Nors ir efektyvesnis būdas nei pirmas, tačiau vistiek turi trūkumų, tarp kurių akivaizdžiausias - naudojimo patogumas. Neišvengiamai tenka visur rašyti SQL (mes juk pripažįstam tik RUBY:), neaiški situacija su Rails migracijomis, ten tenka naudoti šlykštoką 'execute'. Taip pat atsiranda apribojimas, nebegalime indeksuotoje lentelėje naudoti transakcijų, kadangi MySQL indeksavimas reikalauja MyISAM tipo lentelės. Aišku, šis tekstinės paieškos realizavimo būdas efektyvesnis nei pirmas, tačiau toli gražu iki mums įprasto grožio:).

Acts_as_ferret pluginas

Tai pakankamai neseniai atsiradęs ir tikrai vertas dėmesio projektas. Jis naudoja "Ruby" kalba implementuotą "Apache Lucene" indeksuotos paieškos variklį. Diegimas paprastas:

gem install ferret

### įkeliam acts_as_ferret pluginą:

script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret.

### Modelyje, kuriame norime indeksuoti atributus, nurodome:

acts_as_ferret :fields => [:attr1, :attr2]

Perkrovę aplikacijos serverį turime reikalingą funkcionalumą. Galime daryti paiešką naudodami find_by_contents metodą savo modelyje.

@total, @results = People.find_by_contents('Bill+Gates-Windows')

Acts_as_ferret veikimo principas paremtas tuo, kad nurodytus atributus jis stebi(callbacks) aplikacijos lygmenyje ir po pasikeitimų indeksuoja, jeigu dirbant "development" rėžimu paprastame faile Rails aplikacijos 'index' kataloge, jeigu 'production' - atskirame 'Drb' serveryje, kurio konfigūravimas panašus į paprastos DB konfigūravimą (YAML sintakse). Taigi 'find_by_contents' metodas pagal paieškos užklausą iš indeksų surenka atitikusių įrašų 'id' masyvą, ir iš MySQL lentelės išrenka įrašus pagal tuos 'id'.

Acts_as_ferret galimybės - įspūdingos. Galima paieška pagal tam tikrą žymių ('wildcards') sistemą, rastų atitikmenų paryškinimas (panašiai į Google), protingo rūšiavimo (kai vieni įrašai labiau atitinka paiešką nei kiti) galimybė ir t.t. Įdomus acts_as_ferret su MySQL text search palyginimas : full-text-search-in-ruby-on-rails .

Vienintelis rimtas trūkumas, kaip ir daugelyje Rails pluginų:

documentation.nil? == true.

Todėl rimtesnių informacijos šaltinių nedaug:
acts-as-ferret-tutorial
full-text-search-in-ruby-on-rails-3-ferret

Acts_as_sphinx pluginas.

Naudoti acts_as_sphinx pluginą rekomenduočiau tiems, kurie kaifuoja dėl gero greičio (performance). Pagal atsiliepimus, šis pluginas naudojantis kaimyno ruso programuotojo Andrew Aksyonoff sphinx variklį, greitas kaip velnias. Galybėmis 'sphinx' panašus su 'ferret', tačiau kaip žinia visur kur norisi įspūdingo greičio, reikia visai neįspūdingo krapštymosi po žemo lygmens detales. Kruopščios priežiūros reikalaujantis 'sphinx', ne išimtis. Diegimo ir priežiūros etapai šiek tiek atbaidantys. Keista dar ir plugino kūrėjų pozicija, neindeksuoti įrašų aplikacijos lygmenyje. Taigi tektų su kokiu nors išoriniu 'cron' automatiniu užduočių paleidimo mechanizmu kas tam tikrus laiko intervalus atnaujinti indeksus. Rezultate - arba nuolat per DB lenteles 'vaikštantis' išorinis procesas, arba ne realaus laiko paieška, nes tik įvedę įrašą jo tam tikrą laiką nerasime.

Taigi paminėti pluginai, labiau tiktų norint tikrai profesionalaus sprendimo, 'pigiam' kodui pakanka ir tiesioginio MySQL DB naudojimo.

3 comments | no trackbacks

Comments

  1. mid said 30/03/2008 at 18h39 later:

    ferret’as, kaip ir php’ine lucene implementacija zend frameworke, labai pykstasi su indeksavimo ir readinimo performancu.

    rekomenduoju http://lucene.apache.org/solr/ :) rails’ai berods turi act_as_solr.

  2. Saulius Grigaitis said 30/03/2008 at 19h51 later:

    Šlamštas tas ferret’as :), visi keikiasi. Ferret’o bėda ne performance, o tame, kad jis kreivai šleivai implementuotas C kalba, pastoviai indeksas užsilenkinėja. Šiaip ferret’as gana spartus duomenų įterpime, tačiau gana lėtas paieškoje. Na, dar trūkumas tas, kad dažniausiai įterpimas prikabinamas prie modelio after\save callback’o, o ferret’as kartas nuo karto pertvarko indeksą, t.y. kas kokį 1000 įterpimų daro indekso pertvarkymą, tad vartotojas atsako į užklausą laukia kelias minutes :). Tuo tarpu Solr’as lėtas įterpime, bet greitas paieškoje, tačiau interfeisas su Solr’u per XML, o ir pats Solr javainis, taigi jei reikia performanco, tenka naudoti gana sudėtingas schemas ir kaip reikiant pakeisti patį acts\_as\solr. Apskritai, rimta paieškos sistemos integracija reikalauja rimtų pastangų.

  3. mid said 31/03/2008 at 10h24 later:

    na mano atveju tai solr’ui (kaip ir turbut bet kokiam java appsui) duota atskira virtualke, tad indeksavimas uztrunka apie 40 sek.

    be to solr’as labai lengvai vietoje xml’o gali paduoti json’a :)

Trackbacks

Use the following link to trackback from your own site:
http://www.rubyonrails.lt/trackbacks?article_id=21

(leave url/email »)

reCaptcha

   Comment Markup Help Preview comment