Sphinx - o căutare rapidă reală pentru anatolium larin

În zilele noastre este dificil să ne imaginăm un site bun fără funcția de căutare. La ceea ce nu pur și simplu căutați și cu sprijinul morfologiei. În majoritatea cazurilor, sprijin suficient pentru limba rusă și engleza.







Și atunci când a dezvoltat următorul proiect a fost problema de căutare. Tabelele din baza de date nu sunt mici (de la 100.000 de înregistrări), dar, de asemenea, pentru a căuta mai multe, trebuie să căutați imediat mai multe, astfel încât opțiunea cu LIKE '% query%' obișnuită a dispărut de la sine.

Anterior, am folosit motorul de căutare mnoGoSearch. dar amintindu-și stricaciunea API-ului său (uneori impresia a fost scrisă de hindușii cu clasele a 5-aa scolii parohiale) a renunțat la această opțiune.

Ca urmare, există două opțiuni:

  1. Scrieți o căutare bazată pe construirea indexurilor și stocați acești indici, de exemplu, în BerkleyDB;
  2. Nu reinventați roata și utilizați una dintre cele mai rapide motoare de căutare - Sfinxul.

Am ales a doua opțiune :)

Apropo, Sfinxul este un proiect al compatriotului nostru Andrey Aksenov. Este demn de remarcat faptul că Andrew are suficient timp și energie nu numai pentru a îmbunătăți în mod constant proiectul, ci și pentru a participa activ la sprijinirea utilizatorilor, răspunzând în mod pozitiv la întrebările din forumul vorbitor de engleză și rusă. Pentru care vă mulțumește atât de mult!

Și așa, să începem să practicăm. Instalarea este standard și nu cauzează probleme.

Descărcați arhiva cu sursele (cea mai recentă versiune în momentul redactării articolului), despachetați și instalați:

# ./configurează
# face
# make install (ca root)

Sub FreeBSD, după finalizarea acestor trei comenzi, am primit produsul gata de plecare. Dar, în Debian a avut un minut de tinker (deși, prima dată, a durat o jumătate de oră :) și executa:

# sudo aptitude instalare libmysql ++ - dev libmysqlclient15-dev checkinstall

după care totul a funcționat perfect.

Pregătirea

Acum, totul este gata pentru a crea un index (presupun că aveți un proiect cu o bază de date terminată). Baza noastră are următoarea structură:

Vom căuta în numele produsului, descrierea și tag-uri. Așadar, trebuie să creăm un index pentru aceste câmpuri. Pentru a face acest lucru, creați un director 2 / home / Larin / date / - aici vom stoca fișierele index, și / home / Larin / log / - jurnalele imediat și /home/larin/sphinx.conf fișier de configurare

Aceasta este întreaga configurație, Sphinx este gata să înceapă indexarea datelor cu o viteză uriașă :) Pentru mai multe informații despre configurare, accesați site-ul oficial în secțiunea de documentare. Este în limba engleză, dar nu trebuie să provoace dificultăți, este scris simplu și accesibil.

morfologie

Spninx acceptă indexarea (și prin urmare căutarea), luând în considerare morfologia rusă și engleză. Sprijinul pentru morfologie este realizat prin ștanțare.

Stemming este procesul care duce la alegerea bazei unui cuvânt din forme complexe de cuvinte.

Iată liniile din configurația de configurare:

indexare

Începeți crearea indexului:
# indexer -config /home/larin/sphinx.conf -all

Totul, indicele este creat! Să vedem!

Pentru depanarea și verificarea stării de sănătate a indexului, utilitarul de căutare este potrivit. Exemplu de utilizare:
#search -config /home/larin/sphinx.conf frază de căutare

Dar pentru o muncă reală, trebuie să rulați daemonul sphinx - căutat:
# searchd -config /home/larin/sphinx.conf

Totul, demonul a început cu succes (apropo, nu ar fi rău să-l adăugați la pornire :). iar acum putem lucra cu acesta din script-urile PHP, prin API oficial. Biblioteca sphinxapi.php necesară este localizată în interiorul fișierului descărcat în directorul api.

Script script

Asta e tot. Și încă o dată (ca în cazul UML și caching-ului), eram siguri că totul este strălucit pur și simplu :)

Ne pare rău, am făcut totul așa cum a fost descris și a mers la căutare engleză pentru un bang, dar în limba rusă nu este în căutarea.
Problemă: Notă: Indicele nedefinit: se potrivește în /bhome/part3/03/avenirru/avenir.ru/www/test.php pe linia 37

Linia 37 este următoarea: dacă ($ rezultat is_array ($ result ['matches']))

și anume matricea rezultată nu există deoarece nu găsește nimic (((
care a găsit dificultatea căutării în limba rusă?







el a observat
la indexarea la acele ajustări care au fost deduse: indexarea indexului "știri" ...
EROARE: index 'știri': sql_query_pre [0]: sistem Unknown variabila 'NUME' (DSN = mysql: // avenir_ru: ***@baze.avenir.ru: 64000 / avenir_ru).
total 0 docs, 0 octeți
total 0,051 sec, 0,00 octeți / sec, 0,00 docs / sec

Spune că nu înțelege linia: sql_query_pre = SET NAMES cp1251

Ce versiune de MySQL?

Am dat seama la versiunea cu 5 și această eroare a dispărut. Dar căutarea în limba rusă nu merge, actuala engleză

Iată conf. Mea, ajuta la rezolvarea greșelilor (tabele și DB în utf8):
știri sursă
tip = mysql
sql_host = mysql.baze.avenir.ru
sql_user = avenir_en
sql_pass = ******
sql_db = avenir_en
sql_port = 64547

sql_query_pre = Setați CHARACTER_SET_RESULTS = utf8
sql_query_pre = SET NAMES utf8
sql_query_pre = SET SETAREA CARACTERULUI utf8

sql_query = SELECT n.news_id, n.title, n.body FROM "news" n

sql_query_info = SELECT * FROM `news` WHERE` news_id` = $ id
sql_ranged_throttle = 0
>

știri de știri
sursă = știri
calea / / bhome / part3 / 03 / avenirru / sphinx / sphinks / var / date / știri
docinfo = extern
mlock = 0
morfologie = stem_en, stem_en
min_word_len = 2
charset_type = utf-8
charset_table = 0..9, A..Z-> a..z, _, a..z, U + A8-> U + B8, U + B8, U + C0..U + DF-> U + E0..U + FF, U + E0..U + FF
min_infix_len = 2
enable_star = 1
>

searchd
adresa = 127.0.0.1
port = 3312
log = /bhome/part3/03/avenirru/sphinx/sphinks/var/searchd.log
query_log = /bhome/part3/03/avenirru/sphinx/sphinks/var/query.log
read_timeout = 5
max_children = 30
pid_file = /bhome/part3/03/avenirru/sphinx/sphinks/var/searchd.pid
max_matches = 1000

// Și acum afișăm aceste produse sortate după relevanță
$ id_list = implode (',', $ ids);
$ Sql ​​= sprintf ( 'SELECT * FROM `product` WHERE` product_id` IN (% s) ORDER BY FIELD (` product_id`,% s)', $ ID_LIST, $ ID_LIST);

// În continuare vom executa această solicitare și ne bucurăm de rezultate

iar această interogare se realizează prin ce metodă a sfinxului.

Această interogare este efectuată de clasa bazei dvs. de date sau pur și simplu de funcția mysql_query ()))

))) mulțumesc, asta e doar atunci nu este foarte clar și care este creșterea vitezei? Dacă primiți deja 2 solicitări. Primul Sfinx în indici, și apoi, de asemenea, noi în baza de date?
Iartă-mă pentru întrebări stupide.)))

))) mulțumesc, asta e doar atunci nu este foarte clar și care este creșterea vitezei? Dacă primiți deja 2 solicitări. Primul Sfinx în indici, și apoi, de asemenea, noi în baza de date?
Iartă-mă pentru întrebări stupide.)))

Câștigul este că Sfinxul, spre deosebire de MySQL, caută intrări în indexul său cu o viteză gigantică și în toate domeniile.
Și efectuăm o singură cerere (cea cu IN) care este executată foarte repede. deoarece Căutarea se bazează pe cheia primară din tabel. Unde ați văzut cele 2 solicitări.

Când indexați? Deci, acest proces este lansat mult mai rar, în comparație cu cererile de căutare. La mine, pe unele site-uri, reindexarea începe doar o dată pe zi)

Pol_uha. ce altceva nu este clar?

Și dacă toate câmpurile de care am nevoie în tabel au fost indexate, de ce sfinxul doar nu le ia de acolo și nu le scoate, dar trebuie să întreb în continuare baza de date?
Mulțumesc foarte mult, super blog. Am citit alte articole.)))

Sfinxul stochează indexul pe date, nu datele în sine. Înțelegeți diferența?

Sunt bucuros că blogul este ca și ajută)

Înțeleg)))
Și vă puteți ajuta în această sarcină:
Există un tabel cu numele animalelor și cu numele localităților în care se află)))
Două tabele sunt indexate în consecință: acesta și orașele.
Un om a fost introdus de o broasca testoasa de la Moscova sau de o broasca testoasa la Moscova etc.
cum fac interacțiunea acestor două tabele? Ie Sunt toate broaștele țestoase și au verificat id-urile orașelor în care trăiesc și sunt comparate cu idul din tabelul orașelor unde sunt luate numele și comparate cu cel de-al doilea cuvânt, în acest caz "Moscova"?
OWL. ))))

Și deci există 2 mese:
orașul [town_id, town_title] și
animal [animal_id, animal_title, town_id]

În consecință, pentru a crea în mod corespunzător un index, trebuie să le combinați. pentru că vom căuta animale, apoi cheia primară în rezultatele interogării vom avea animal_id.
Avem:
sql_query = SELECT animal_id, animal_title, town_title DE LA `animal` o localitate STÂNGA JOIN` t ON a.town_id = t.town_id

Toate))) Acum, indexul va fi construit corect: căutarea va fi efectuată în funcție de numele orașului și de numele animalului.

ZY LEFT JOIN se face pentru cazul în care nu toate animalele au un anumit oraș de reședință.

Bună ziua))) Încercați din nou. În loc de voi veți cere, ca într-o sfinxă, să faceți o căutare absolută. Ie când intri în "hipopot negru"
el nu a dat toate intrările unde se spune "negru" și "hipopotam" separat, dar numai unde este întreaga frază?

Întreaga problemă este că căutare normală MySQL este foarte lentă.

Interogarea este după cum urmează:

Ie folosit ca "% ...%". Documentația spune că atunci când utilizați ca "% ...%", indicii nu funcționează și este folosit un fel de "Turbo Boyer-Moore algorythm" (similar).
Funcționează foarte încet. Nu am așteptat până la sfârșitul căutării nici măcar două entități.

Căutarea după acord este o căutare în trei. Am decis să folosesc Sfinxul. SphinxQL, deoarece este mai ușor să o rescrieți.

Acum, după cum înțeleg, este necesar să se facă trei surse:
1.) Est. clienții.
2.) Est. TC.
3.) Est. contracte.

Și trei indici:
1.) Clientul are nevoie de un indice de 1.
2.) TS are un proprietar, adică pe TS aveți nevoie de un indice de 1 și 2.
3.) Pentru contractele de la 1, 2, 3.

Problema este că, în primul rând, nu am așteptat până la sfârșitul creării indexului, cel puțin de către clienți (dar numai în tabel

15500 intrări).
Se creează indexul de testare pe masă cu 149 de intrări.
De ce atât de mult? Ce fac greșit?
În al doilea rând, aș dori să primesc date, nu ID.
Este posibil să faceți acest lucru folosind instrumente Sphinx (de exemplu, pentru a face o cerere la MySQL)?







Trimiteți-le prietenilor: