Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: wyszukiwarka
Forum PHP.pl > Forum > PHP > Pro
chmolu
Witam,

wiem, że takie tematy już były, ale nie znalazłem w nich żadnych konkretów.

Jak podeszlibyście do problemu zbudowania mechanizmu wyszukiwarki dla systemu, który nierzadko może obsługiwać spore ilości danych (w wielu tabelach)?

Interesuje mnie wszystko na ten temat - linki, artykuły, tutoriale.

Spotkałem się już w kilku aplikacjach z rozwiązaniem, które wyglądało mniej więcej tak:
treść tabeli, np. articles jest dzielona na słowa, np tekst:
Cytat
To jest przykładowa treść artykułu

Zostanie podzielony na tablicę:
  1. <?php
  2. array('jest', 'przykładowa', 'treść', 'artykułu');
  3. ?>

Słowo "to" jest traktowane jako tzw. common word i pomijane.

Te słowa są wrzucane do osobnej tabeli, która ma mniej wiecej taką strukturę:
Kod
word_id
word_text


Do tego jest jeszcze jedna tabela, która łączy artykuł ze słowami:
Kod
article_id
word_id



Rozwiązanie ciekawe, ale zastanawia mnie, jak to jest z jego wydajnością. O ile liczba słów jest ograniczona, to druga tabela może się nieźle rozrosnąć. Pisał już ktoś coś takiego? Jakie są wasze sposoby na problem wyszukiwarki w CMSach?
dtb
http://www.phpsolmag.org/pl/modules/news2/....php?storyid=13 <- w gazecie jest art jak zrobic wyszykiwarke używając zbiorów (BITSET). polecam.
chmolu
Z tego, co pamiętam to rozszerzenie BitSet nie jest standardowo dołączane do php, więc takie rozwiązanie odpada.

Jak na razie najrosądniejszym rozwiązaniem byłoby zastosowanie FULLTEXT search MySQL'a. Jest jednak ten problem, że definitywnie tracę tu kompatybilność z innymi systemami RDBMS :/
bela
http://lucene.apache.org/ - Javove ale zawsze można popatrzeć.
SongoQ
Wyszukiwanie zalezy od rodzaju bazy, niektore wspomagaja takiego typu przeszukiwania. Odnosnie takiego schematu, to sam mam zaimplementowane w jednej aplikacji i indeksow slow jest chyba okolo 10 milionow i czasu sa bardzo zadowalajace. Wszystko zalezy od bazki i umiejetnosci dostrojenia zapytania.
chmolu
Niestety muszę wrócić do tej sprawy.

Przez głupi bug w mysqlu FULLTEXT mogę sobie o d**ę potłuc. I chyba nie zanosi się na szybkie naprawienie tego - bug został oznaczony jako "closed". Szkoda, bo w tej chwili wyszukiwarka u mnie to 2 zapytania...

Jak wyszukiwarki zaimplementowane są w IPB, ezPublish i innych tego typu systemach?

Jak sprawa wygląda na Postgresie? Czy można na nim zbudować jakąś wydajną wyszukiwarkę w miarę prosty sposób?
bela
Tsearch2?
Bora
Cytat(chmolu @ 2005-12-04 00:48:17)
Do tego jest jeszcze jedna tabela, która łączy artykuł ze słowami:
Kod
article_id
word_id



Rozwiązanie ciekawe, ale zastanawia mnie, jak to jest z jego wydajnością. O ile liczba słów jest ograniczona, to druga tabela może się nieźle rozrosnąć. Pisał już ktoś coś takiego? Jakie są wasze sposoby na problem wyszukiwarki w CMSach?

Może w takim razie zmienić sposób przechowywania danych w tej tabeli.
Np 1|34|43
albo nawet złączyć to w jedną tabele:
word_id | word | articles
potem tylko expolde albo coś w tym stylu. Żeby nie meczyć sie za bardzo wystarczy tylko dac odpowiednie API żeby przy każdym dodaniu/edycji/usunięciu modyfikowało odpowiednie rekordy.
ActivePlayer
a jak wyliczyc trafność ?
chmolu
A jak ma się sprawa z LIKE %cośtam%?

Czy jeśli mam napchaną tabelę, w której przeszukiwać chcę 2 pola o wielkości 1-4 zdań, to LIKE będzie bardzo zabójcze dla bazy?

edit:
znalazłem fajny tutorial: http://www.symfony-project.com/askeet/21
Chyba zaimplementuję sobie coś takiego. Więcej roboty, baza się rozrośnie, ale może będzie działało, jak należy smile.gif
SongoQ
LIKE jest zabojczy dla baz tongue.gif
ergo
ja chyba czegos nie rozumiem , bo o ile mi sie wydaje to dal kazdego slowa ktore mialo by byc umieszczone generowane jest zapytanie ? pozatym trzeba by sprawdzic czy slowo znajduje sie w bazie, w jaki sposob to wygodnie zaimplementowac ?
pawkow
Według was należy ograniczać używanie LIKE. Rozumiem. A może używać LIKE i zapisywać w bazie otrzymane wyniki. Wtedy jeśli pojawiło by się nowe słowo, tworzony byłby nowy rekord. Przykład:

internauta poszukuje słowa "analfabetyzm" na naszej stronie.

1. Jeżeli ktoś już szukał tego słowa wcześniej, to mamy problem z głowy.
2. Jeśli nie baza przeszukuje artykuły, i zapisuje id artykułów w bazie w tabeli o strukturze jak niżej:

Kod
| search_id | search_result |


W search_id wiadomo, w search result oddzielone jakimś znakiem, np: "|" id konkretnego artykułu. Potem tylko explode w wypadku kolejnego wyszukania tego słowa i mamy gotowe wyniki.

Gorzej, jeżeli chcemy umożliwić przeszukiwanie całego portalu, np. newsów, userów i artykułów. Jednak i to można rozwiązać, zapuisując wyniki np. w takiej postaci: a1|a17|a26|n4|n78|n54|u14|u56|u8

Były by to:
artykuły o id 1, 17, 26
newsy o id 4, 78, 54
userzy o id 14, 56, 8


Może komuś się takie rozwiązanie spodoba winksmiley.jpg

// EDT do postu wyżej

Może być jedno zapytanie np: LIKE %slowo 1% AND LIKE %slowo 2%
Sedziwoj
pawkow to rozwiązanie jest kiepskie, ponieważ przy pojawieniu się nowego artykułu, nie masz możliwości usunięcia bufora. A jakbyś to robił, to by było takie samo obciążenie, jak przy użyciu samego LIKE. Przy każdym wybraniu musiał byś rozdzielać dane, co też generuje obciążenie.
Jeszcze sam nie wnikałem w ten problem, ale przy tym co się chwile zastanowiłem, to chyba najlepsze rozwiązanie to
word | id_article
przy czym unikalne jedynie mogło by być połączenie obu.
Przy założeniach szukania samego artykułu bez cytatu.
Bo chyba jednak problem nie może być rozwiązany aby był mało obciążający pamięciowo i obliczeniowo.
Turgon
W mojej opinii otagowywać i na ich podstawie szukać. Obecnie sam piszę przeszukiwarkę artów, to napiszę coś więcej.
Martio
Cytat(ActivePlayer @ 15.01.2006, 20:39:19 ) *
a jak wyliczyc trafność ?


Polecam komponent Zend_Search z frameworka Zend Framework oparty o projekt Apache Lucene. Jest to najbardziej optymalne rozwiązanie, gdyż opiera się w całości na indeksacji danych w systemie plików. Wyszukiwanie w bazie danych ma wiele wad: czas wyszukiwania różni się od ilość danych, jest to spore obciążenie dla samej bazy danych, itd.

W wynikach wyszukiwania masz już obliczone trafność wyszukiwania, a mierzy się to następującym wzorem:

  1. <?php
  2. score(q,d) = sum( tf(t in d) * idf(t) * getBoost(t.field in d) * lengthNorm(t.field in d) ) * coord(q,d) * queryNorm(q)
  3. ?>
zbig
Mysle , ze temat wyszukiwarek jest zbyt wielki zeby wszystkie watpliwosci rozwiac podczas dyskusji na forum.
Pracuje kilka lat w niemieckiej firmie specjalizujacej sie w aplikacjach webowych i moge jedynie napisac kilka slow o naszym sposobie. Przede wszystkim na podstawie danych ktore moga byc wyszukiwane przez uzytkownikow generujemy specjany text index , ktory pozwala na natychmiastowe (prawie) znalezienie danych.
Text index to tylko nazwa tak naprawde dane dla wyszukiwarki moga byc trzymane w tabeli w bazie. Najwazniejsza jednak rzecz to budowa indexu w taki sposob aby mozna bylo uzyc algorytmu DFA do jego przeszukiwania.
Jest to standartowy algorytm uzywany przez MYSQL do tworzenia text indexow przy FULLTEXT , ale w naszym przypadku FULLTEXT MYSQL tworzy zbyt ogolny text index, dlatego tworzymy sobie wlasny absolutnie indywidualny dla naszych danych. Nastepnym krokiem jest wlasnie owa wyszukiwarka ktora zgodnie z DFA przeszuka caly text index i zwroci nam resultat , counter i tym podobne rzeczy. Text index jest odswiezany raz dziennie , czyli tak na prawde dane wprowadzone dzisiaj moga byc widoczne, dopiero nastepnego dnia.

W naszym przypadku potrzebne sa trzy aplikacje
1. tworzaca indexy (Java lub C++)
2. nasluchujaca (Java lub C++)
3. przeszkujaca indexy wg DFA (Java lub C++)

no i oczywiscie cos co to wszystko wyswietli (PHP)
Do komunikacji PHP z Java uzywamy JavaBridge ,z C++ Ajaxa z responseXML

Na podobnej zasadzie (ale na 100% o wiele lepiej pracujacej) bazuja Google, mam na mysli algorytm DFA
A tak na marginesie nalezy dodac ze Google rowniez uzywaja MYSQL-a , co powinno zakonczyc dyskusje na temat waznosci swiat Bozego Narodzenia na Wielka Noca smile.gif

Powinienem dodac , ze text index w naszym przypadku trzymany jest w pamieci aplikacji nasluchujacej ,ale jest to indywidualny wybor, dane mozna trzymac w tabelach chociaz chodzi to nieco wolniej.

Nasza wyszukiwarka przeszkuje baze danych 2 milionow firm polaczonych z kategoriami , oraz 40 milionach danych adresowych . Musze przyznac ze textindexy osigaja kilkugigowe rozmiary ale algorytm pozwala absolutnie szybko eliminowac niepotrzebne kroki podczas wyszukiwania.

Na zakonczenie chcialbym dodac , ze nie widze absolutnie zadnego prolemu w napisaniu calego mechanizmu w PHP

Wyszukiwarka ta pracuje na stronie http://city24.de/YellowPages
Wiecej szczegolow podac niestety nie moge ale zachecam do zapoznania sie z DFA i mam nadzieje ze pomysly z jego wykorzystanim nasuna sie Wam same

Pozdrawiam
Riklaunim
jest też Xapian - http://www.xapian.org/ który ma API dostępne dla Ruby, Pythona, PHP i innych. Ostatnio bawiłem się API pythonowym, wersja PHP w planach i działa całkiem fajnie smile.gif Problemem może być brak "przyjaznych" tutoriali. (+ konieczność zainstalowania xapiana i xapian-bindings na serwerze)
SHiP
Cytat(Sedziwoj @ 26.03.2007, 22:24:19 ) *
pawkow to rozwiązanie jest kiepskie, ponieważ przy pojawieniu się nowego artykułu, nie masz możliwości usunięcia bufora. A jakbyś to robił, to by było takie samo obciążenie, jak przy użyciu samego LIKE. Przy każdym wybraniu musiał byś rozdzielać dane, co też generuje obciążenie.
Jeszcze sam nie wnikałem w ten problem, ale przy tym co się chwile zastanowiłem, to chyba najlepsze rozwiązanie to
word | id_article
przy czym unikalne jedynie mogło by być połączenie obu.
Przy założeniach szukania samego artykułu bez cytatu.
Bo chyba jednak problem nie może być rozwiązany aby był mało obciążający pamięciowo i obliczeniowo.


Można cachować zapytania wyszukiwarki i to w bardzo prosty sposób, wystarczy do każdego artykułu dodać jedno pole "searchid"

I tłumaczac na przykładzie:
1. Dodajemy artykuł i przypisujemy mu searchid=1
2. Nic nie mamy zcachowane wiec nasza zmienna w wyszukiwarce, $cache=1,
3. Następuje pierwsze wyszukiwanie wszystkich artykułów których searchid >= $cache
4. Zwiększamy naszą zmienną wyszukiwarki $cache do 2,
5. Dodajemy artykuł, tym razem jako searchid dodajemy wartosc naszej zmiennej $cache czyli dwa
6. Następuje kolejne wyszukiwanie, cachujemy artykuły o searchid>=$cache
I tak w kółko

W przypadku usuwania artykułów sprawa jest prosta, w przypadku edycji po prostu zmieniamy searchid w artykulu na $cache+1

Lepszego sposobu nie wymysliłem, jedyny problem to przechowywanie zmiennej $cache gdzies w globalnym miejscu aby zapytania łatwo mogły się do niej odwołac.
rashid
Cytat(zbig @ 5.05.2007, 14:55:38 ) *
W naszym przypadku potrzebne sa trzy aplikacje
1. tworzaca indexy (Java lub C++)
2. nasluchujaca (Java lub C++)
3. przeszkujaca indexy wg DFA (Java lub C++)

no i oczywiscie cos co to wszystko wyswietli (PHP)
Do komunikacji PHP z Java uzywamy JavaBridge ,z C++ Ajaxa z responseXML


No bez perwy... Google daje rade indeksowac skryptami w Pythonie, wiec nie widze najmniejszego problemu z zaprzegnieciem PHP do tej samej funkcji, szczegolnie do indeksowania danych stanowiacych jakis pikoprocent danych, na ktorych operuje Google.

Cytat(zbig @ 5.05.2007, 14:55:38 ) *
Na podobnej zasadzie (ale na 100% o wiele lepiej pracujacej) bazuja Google, mam na mysli algorytm DFA
A tak na marginesie nalezy dodac ze Google rowniez uzywaja MYSQL-a , co powinno zakonczyc dyskusje na temat waznosci swiat Bozego Narodzenia na Wielka Noca smile.gif


MySQL nie jest uzywany do przechowywania indeksu Google. Jest uzywany w innych aplikacjach, np. do gromadzenia statystyk Google Analytics (strzelam tutaj bazujac na tym, ze Urchin stanowiacy baze dla GA korzystal z tego).


Odpowiadajac na glowne pytanie tego watku, jesli ktos chce pisac samodzielnie wydajna wyszukiwarke, to polecam http://labs.google.com/papers.html (tutaj miedzy innymi artykuly o sposobie przechowywania danych glownego indeksu Google). Dla wiekszosci powaznych rozwiazan lepsze na dluzsza mete bedzie skorzystanie z gotowca, czyli http://www.google.com/enterprise/mini/.

PS. Nie mam ochoty na dyskusje o nieosiagalnosci Mini z powodow finansowych.
jupeter
Ja znalazłem dobre rozwiązanie na indekser podglądając kod MediaWiki. Wykorzystuje ona full-text różnych baz danych (na pewno był tam: MySQL, PostgreSQL i Oracle).
Patrząc na wykorzystanie tych skryptów na dużą skalę (Wikipedia - duże obciążenie + duża ilość zapytań w wyszukiwarkę) to wg mnie zachowuje się wzorowo.

U mnie sprawdza się przy ok. 80 tyś. zasobów. Wyszukuje w 95% poniżej 0,05 sekundy.

Cytat(rashid @ 10.05.2007, 10:11:48 ) *
No bez perwy... Google daje rade indeksowac skryptami w Pythonie, wiec nie widze najmniejszego problemu z zaprzegnieciem PHP do tej samej funkcji, szczegolnie do indeksowania danych stanowiacych jakis pikoprocent danych, na ktorych operuje Google.


Hehe. Wszystko kwestia ilości zasobów i wielkości serwera/serwerów. Jak masz mało zasobów dziennie i mało obciążony serwer/y, to możesz i na PHP winksmiley.jpg. Przy dużej skali, to nie wiem czy byłbyś tak zadowolony z indeksera w samym PHP, gdyby nie wyrabiał dziennego zbioru do zaindeksowania + non stop CPU na 100% .
AcidBurnt
fajny przykład na PostgreSQL:

http://www.depesz.com/index.php/2007/06/11...y-rozszerzanie/
rubinek
Sphinx -> http://www.sphinxsearch.com/ -> i posprzatane smile.gif

Jak wszystko ma swoje wady (trzeba go karmic danymi) ale jest baaaaaardzo szybki
Strzałek
Jednak nie każdy ma możliwość instalacji na swoim serwerze Sphinx'a.

Po za tym - ktoś tego używa? Wygląda bardzo interesującą.
c3zi
Tak, ktoś używa. Jest bardzo wydajny jeśli chodzi o wyszukiwanie. Do tego indeksy również dosyć szybko przebudowuje (oczywiście zależy od rozmiaru),
ale nie trwa to zazwyczaj więcej niż kilka minut (to już naprawdę duży indeks musi być!).

Konfiguracja też jest rozbudowana i dobrze opisana w dokumentacji lub wiki sphinx'a(aczkolwiek często 3ba sięgać do forum). No i do tego dosyć fajne api do PHP. Można nakładać wagi na poszczególne kolumny z bazy i wiele innych ;-)
NuLL
A czy Sphinx potrafi indeksowac kilka tabel z danymi i wypluc wynik wyszukiwania na bazie trafnosci ze wsystkich tabel lacznie ?
rashid
Sphinx indeksuje dane z dowolnego zapytania, wiec mozesz tez porobic JOINy w tym zapytaniu. Jest sporo mozliwosci konfiguracyjnych, z penwoscia uzywajac Sphinxa bedziesz w stanie cos takiego zrealizowac, chociaz byc moze czesciowo z logika poza Sphinxem.
kosmowariat
Cytat(bela_666 @ 4.12.2005, 10:42:11 ) *
http://lucene.apache.org/ - Javove ale zawsze można popatrzeć.


W php też można korzystac z lucene. Polecam Zend_Search_Lucene (http://framework.zend.com/manual/en/zend.search.lucene.html)
Strzałek
Cytat(NuLL @ 27.01.2009, 15:54:10 ) *
A czy Sphinx potrafi indeksowac kilka tabel z danymi i wypluc wynik wyszukiwania na bazie trafnosci ze wsystkich tabel lacznie ?



Tak, można ustawić wagi dla poszczególnych pól wg. których będzie sumować trafność i dużo innch ciekawych rzeczy.

Używałem Sphinxa razem z Railsami (Thinking Sphinx) i tam tak można było zrobić. Nie wiem czy to zostało zaprogramowane w pluginie czy sam sphinx to potrafi. Myślę jednak że to siedzi w sphinxie.
ropsiU
A próbował się ktoś z polską morfologią w sphinxie?

Z tego, czego się doszukałem wynika, że bez rozszerzeń są dostępne morfologie angielska i rosyjska (conf-morphology), ale da się doinstalować stemmery do języków: danish, dutch, english, finnish, french, german, hungarian, italian, norwegian, portuguese, romanian, russian, spanish, swedish, turkish.

Jak widać polskiego tu nie ma sad.gif Da się to jakoś rozsądnie rozwiązać?
pawel_
Ja używam czegoś takiego ( w sekcji index )
Kod
charset_table =  0..9, a..z, _, A..Z->a..z, U+00C0->a, U+00C1->a, U+00C2->a, U+00C3->a, U+00C4->a, U+00C5->a, U+00C7->c, U+00C8->e, U+00C9->e, U+00CA->e, U+00CB->e, U+00CC->i, U+00CD->i, U+00CE->i, U+00CF->i, U+00D1->n, U+00D2->o, U+00D3->o, U+00D4->o, U+00D5->o, U+00D6->o, U+00D9->u, U+00DA->u, U+00DB->u, U+00DC->u, U+00DD->y, U+00E0->a, U+00E1->a, U+00E2->a, U+00E3->a, U+00E4->a, U+00E5->a, U+00E7->c, U+00E8->e, U+00E9->e, U+00EA->e, U+00EB->e, U+00EC->i, U+00ED->i, U+00EE->i, U+00EF->i, U+00F1->n, U+00F2->o, U+00F3->o, U+00F4->o, U+00F5->o, U+00F6->o, U+00F9->u, U+00FA->u, U+00FB->u, U+00FC->u, U+00FD->y, U+00FF->y, U+0100->a, U+0101->a, U+0102->a, U+0103->a, U+0104->a, U+0105->a, U+0106->c, U+0107->c, U+0108->c, U+0109->c, U+010A->c, U+010B->c, U+010C->c, U+010D->c, U+010E->d, U+010F->d, U+0112->e, U+0113->e, U+0114->e, U+0115->e, U+0116->e, U+0117->e, U+0118->e, U+0119->e, U+011A->e, U+011B->e, U+011C->g, U+011D->g, U+011E->g, U+011F->g, U+0120->g, U+0121->g, U+0122->g, U+0123->g, U+0124->h, U+0125->h, U+0128->i, U+0129->i, U+012A->i, U+012B->i, U+012C->i, U+012D->i, U+012E->i, U+012F->i, U+0130->i, U+0134->j, U+0135->j, U+0136->k, U+0137->k, U+0139->l, U+013A->l, U+013B->l, U+013C->l, U+013D->l, U+013E->l, U+0141->l, U+0142->l, U+0143->n, U+0144->n, U+0145->n, U+0146->n, U+0147->n, U+0148->n, U+014C->o, U+014D->o, U+014E->o, U+014F->o, U+0150->o, U+0151->o, U+0154->r, U+0155->r, U+0156->r, U+0157->r, U+0158->r, U+0159->r, U+015A->s, U+015B->s, U+015C->s, U+015D->s, U+015E->s, U+015F->s, U+0160->s, U+0161->s, U+0162->t, U+0163->t, U+0164->t, U+0165->t, U+0168->u, U+0169->u,U+016A->u, U+016B->u, U+016C->u, U+016D->u, U+016E->u, U+016F->u, U+0170->u, U+0171->u, U+0172->u, U+0173->u, U+0174->w, U+0175->w, U+0176->y, U+0177->y, U+0178->y, U+0179->z, U+017A->z, U+017B->z, U+017C->z, U+01A0->o, U+01A1->o, U+01AF->u, U+01B0->u, U+01CD->a, U+01CE->a, U+01CF->i, U+01D0->i, U+01D1->o, U+01D2->o, U+01D3->u, U+01D4->u, U+01D5->u, U+01D6->u, U+01D7->u, U+01D8->u, U+01D9->u, U+01DA->u, U+01DB->u, U+01DC->u, U+01DE->a, U+01DF->a, U+01E0->a, U+01E1->a, U+01E6->g, U+01E7->g, U+01E8->k, U+01E9->k, U+01EA->o, U+01EB->o, U+01EC->o, U+01ED->o, U+01F0->j, U+01F4->g, U+01F5->g, U+01F8->n, U+01F9->n, U+01FA->a, U+01FB->a, U+0200->a, U+0201->a, U+0202->a, U+0203->a, U+0204->e, U+0205->e, U+0206->e, U+0207->e, U+0208->i, U+0209->i, U+020A->i, U+020B->i, U+020C->o, U+020D->o, U+020E->o, U+020F->o, U+0210->r, U+0211->r, U+0212->r, U+0213->r, U+0214->u, U+0215->u, U+0216->u, U+0217->u, U+0218->s, U+0219->s, U+021A->t, U+021B->t, U+021E->h, U+021F->h, U+0226->a, U+0227->a, U+0228->e, U+0229->e, U+022A->o, U+022B->o, U+022C->o, U+022D->o, U+022E->o, U+022F->o, U+0230->o, U+0231->o, U+0232->y, U+0233->y, U+1E00->a, U+1E01->a, U+1E02->b, U+1E03->b, U+1E04->b, U+1E05->b, U+1E06->b, U+1E07->b, U+1E08->c, U+1E09->c, U+1E0A->d, U+1E0B->d, U+1E0C->d, U+1E0D->d, U+1E0E->d, U+1E0F->d, U+1E10->d, U+1E11->d, U+1E12->d, U+1E13->d, U+1E14->e, U+1E15->e, U+1E16->e, U+1E17->e, U+1E18->e, U+1E19->e, U+1E1A->e, U+1E1B->e, U+1E1C->e, U+1E1D->e, U+1E1E->f, U+1E1F->f, U+1E20->g, U+1E21->g, U+1E22->h, U+1E23->h, U+1E24->h, U+1E25->h, U+1E26->h, U+1E27->h, U+1E28->h, U+1E29->h, U+1E2A->h, U+1E2B->h, U+1E2C->i, U+1E2D->i, U+1E2E->i, U+1E2F->i, U+1E30->k, U+1E31->k, U+1E32->k, U+1E33->k, U+1E34->k, U+1E35->k, U+1E36->l, U+1E37->l, U+1E38->l, U+1E39->l, U+1E3A->l, U+1E3B->l, U+1E3C->l, U+1E3D->l, U+1E3E->m, U+1E3F->m,U+1E40->m, U+1E41->m, U+1E42->m, U+1E43->m, U+1E44->n, U+1E45->n, U+1E46->n, U+1E47->n, U+1E48->n, U+1E49->n, U+1E4A->n, U+1E4B->n, U+1E4C->o, U+1E4D->o, U+1E4E->o, U+1E4F->o, U+1E50->o, U+1E51->o, U+1E52->o, U+1E53->o, U+1E54->p, U+1E55->p, U+1E56->p, U+1E57->p, U+1E58->r, U+1E59->r, U+1E5A->r, U+1E5B->r, U+1E5C->r, U+1E5D->r, U+1E5E->r, U+1E5F->r, U+1E60->s, U+1E61->s, U+1E62->s, U+1E63->s, U+1E64->s, U+1E65->s, U+1E66->s, U+1E67->s, U+1E68->s, U+1E69->s, U+1E6A->t, U+1E6B->t, U+1E6C->t, U+1E6D->t, U+1E6E->t, U+1E6F->t, U+1E70->t, U+1E71->t, U+1E72->u, U+1E73->u, U+1E74->u, U+1E75->u, U+1E76->u, U+1E77->u, U+1E78->u, U+1E79->u, U+1E7A->u, U+1E7B->u, U+1E7C->v, U+1E7D->v, U+1E7E->v, U+1E7F->v, U+1E80->w, U+1E81->w, U+1E82->w, U+1E83->w, U+1E84->w, U+1E85->w, U+1E86->w, U+1E87->w, U+1E88->w, U+1E89->w, U+1E8A->x, U+1E8B->x, U+1E8C->x, U+1E8D->x, U+1E8E->y, U+1E8F->y, U+1E96->h, U+1E97->t, U+1E98->w, U+1E99->y, U+1EA0->a, U+1EA1->a, U+1EA2->a, U+1EA3->a, U+1EA4->a, U+1EA5->a, U+1EA6->a, U+1EA7->a, U+1EA8->a, U+1EA9->a, U+1EAA->a, U+1EAB->a, U+1EAC->a, U+1EAD->a, U+1EAE->a, U+1EAF->a, U+1EB0->a, U+1EB1->a, U+1EB2->a, U+1EB3->a, U+1EB4->a, U+1EB5->a, U+1EB6->a, U+1EB7->a, U+1EB8->e, U+1EB9->e, U+1EBA->e, U+1EBB->e, U+1EBC->e, U+1EBD->e,U+1EBE->e, U+1EBF->e, U+1EC0->e, U+1EC1->e, U+1EC2->e, U+1EC3->e, U+1EC4->e, U+1EC5->e, U+1EC6->e, U+1EC7->e, U+1EC8->i, U+1EC9->i, U+1ECA->i, U+1ECB->i, U+1ECC->o, U+1ECD->o, U+1ECE->o, U+1ECF->o, U+1ED0->o, U+1ED1->o, U+1ED2->o, U+1ED3->o, U+1ED4->o, U+1ED5->o, U+1ED6->o, U+1ED7->o, U+1ED8->o, U+1ED9->o, U+1EDA->o, U+1EDB->o, U+1EDC->o, U+1EDD->o, U+1EDE->o, U+1EDF->o, U+1EE0->o, U+1EE1->o, U+1EE2->o, U+1EE3->o, U+1EE4->u, U+1EE5->u, U+1EE6->u, U+1EE7->u, U+1EE8->u, U+1EE9->u, U+1EEA->u, U+1EEB->u, U+1EEC->u, U+1EED->u, U+1EEE->u, U+1EEF->u, U+1EF0->u, U+1EF1->u, U+1EF2->y, U+1EF3->y, U+1EF4->y, U+1EF5->y, U+1EF6->y, U+1EF7->y, U+1EF8->y, U+1EF9->y
mr__y
Cytat(ropsiU @ 27.11.2009, 12:16:33 ) *
A próbował się ktoś z polską morfologią w sphinxie?

Z tego, czego się doszukałem wynika, że bez rozszerzeń są dostępne morfologie angielska i rosyjska (conf-morphology), ale da się doinstalować stemmery do języków: danish, dutch, english, finnish, french, german, hungarian, italian, norwegian, portuguese, romanian, russian, spanish, swedish, turkish.

Poszukaj w google "morfologik".

W sphinxie jest możliwy jest stemming słownikowy, potrzebny jest plik tekstowy z parami wyrazów:
wyraz>forma podstawowa
wyraz>forma podstawowa
wyraz>forma podstawowa
...

Słownik z takimi parami dla języka polskiego można na pewno gdzieś dorwać w internecie smile.gif
Oczywiście taki słownik jest bardzo duży (kilka milionów par) i trochę odbije się to na wydajności samego Sphinx'a. Wzrośnie nie tylko czas indeksowania (co zazwyczaj nie jest takim dużym problemem) ale także czas wyszukiwania. W LF24.pl rozwiązaliśmy to trochę inaczej - stemming przeprowadzany jest "zewnętrznie", za pomocą memcached.
Indeksowanie nie odbywa się za pomocą xmlpipe2 - tzn. Sphinx nie indeksuje bezpośrednio z bazy, tylko plik XML generowany za pomocą skryptu. (Format tego pliku jest opisany w dokumentacji Sphix'a).
W czasie generowania tego pliku wszystkie wyrazy są stemmowane. Podobnie przed przesłaniem zapytania do bazy, wszystkie wyrazy są również stemmowane. Wymaga to trochę zabawy, ale pozwoliło skrócić czas wyszukiwania prawie dwukrotnie smile.gif
Jeśli baza nie jest jakaś gigantyczna a te kilka milisekund czasu wyszukiwania nie jest kluczowe można zostać przy prostszym rozwiązaniu stemming słownikowy w Sphinxie - opcja wordforms w Sphinxie.

Można ewentualnie pokusić się o napisanie własnego stemmera algorytmicznego dla języka polskiego - wydaje mi się, że widziałem taki projekt, więc jest to w ogóle możliwe smile.gif
pawel_
Skrypcik:
Kod
<?php

    # ten plik ściągamy z http://www.sjp.pl/slownik/odmiany/
    echo "Pobieranie słownika odmian\n";
    passthru("wget http://sjp.pl/slownik/odmiany/sjp-odm-20090114.tar.gz -O sjp-odm-20090114.tar.gz");
    passthru("rm -rf odm.txt");
    passthru("tar zxf sjp-odm-20090114.tar.gz");

    $uchwyt = fopen("odm.txt", "r");
    $zapis = fopen("odmiany.sphinx", "w+");

    // odmiany

    echo "Jedna kropka to 1000 słów\n";

    echo "Tworzenie słownika odmian\n";
    $i = 0;
    while (!feof($uchwyt)) {
        $linia = explode(", ", fgets($uchwyt));
        $pierwszy = trim(array_shift($linia));
        if (!empty($pierwszy)) {
            fwrite($zapis, $pierwszy.' > '.implode(' ', $linia));
        }
        if ((++$i%1000) == 0) {
            echo ".";
        }
    }
    fclose($uchwyt);
    fclose($zapis);

    # ten natomiast z http://synonimy.ux.pl/
    echo "Pobieranie słownika synonimów\n";
    passthru("wget http://switch.dl.sourceforge.net/sourceforge/synonimy/thesaurus-1.5.txt.gz -O thesaurus-1.5.txt.gz");
    passthru("gunzip thesaurus-1.5.txt.gz");

    // tezaurus

    echo "\nJedna kropka to 100 słów";

    echo "\nTworzenie słownika synonimów\n";
    $uchwyt = fopen("thesaurus-1.5.txt", "r");
    $i = 0;
    while (!feof($uchwyt)) {
        $linia = explode(";", fgets($uchwyt));
        $pierwszy = trim(array_shift($linia));
        if (!empty($pierwszy)) {
            fwrite($zapis,$pierwszy.' > '.$pierwszy."\n");
            if (!empty($linia)) {
                foreach ($linia as $wyraz) {
                    if (false === strpos($wyraz, ' ')) {
                        fwrite($zapis,trim($wyraz).' > '.$pierwszy."\n");
                    }
                }
            }
        }
        if ((++$i%1000) == 0) {
            echo ".";
        }
    }


Było aktualne w wakacje, mogły się linki pozmieniać. Odpalasz i masz odpowiedni plik z odmianami i bliskoznacznymi.
W indexie dodajesz
wordforms = /<sciezka>/odmiany.sphinx
Mikz
Cytat(Sedziwoj @ 27.03.2007, 00:24:19 ) *
pawkow to rozwiązanie jest kiepskie, ponieważ przy pojawieniu się nowego artykułu, nie masz możliwości usunięcia bufora. A jakbyś to robił, to by było takie samo obciążenie, jak przy użyciu samego LIKE. Przy każdym wybraniu musiał byś rozdzielać dane, co też generuje obciążenie.
Jeszcze sam nie wnikałem w ten problem, ale przy tym co się chwile zastanowiłem, to chyba najlepsze rozwiązanie to
word | id_article
przy czym unikalne jedynie mogło by być połączenie obu.
Przy założeniach szukania samego artykułu bez cytatu.
Bo chyba jednak problem nie może być rozwiązany aby był mało obciążający pamięciowo i obliczeniowo.


Sedziwoj, nie jestem przekonany co do tego co mówisz. Znaczy oczywiście nie pozbywamy się obciążającego LIKE'a, ale można zrobić relację many-to-many zamiast takiej dziwnej kolumny z separatorami | i przy ponownym wyszukiwaniu takim zapytaniem z LIKE określić w WHERE tylko te rekordy których czas utworzenia lub modyfikacji jest późniejszy niż czas utworzenia rekordu wyszukiwania. To tak bez wdawania się w niepotrzebne szczegóły.
Za to problem który widzę to dodatkowe obciążenie bazy przy zapisywaniu wyników wyszukiwania, literówki popełnione przez wyszukujących i tak dalej

pawel_ - dzięki za ten skrypt, a właściwie za metodę z tymi słownikami smile.gif


Odnośnie budowania indeksu słów, takie rozwiązanie stosuje np. phpBB.
Wave
Na czym polega wyszukiwanie z użyciem indeksu słów?

Jak rozwiązujecie kwestię wyznaczania popularnych wyszukiwań?
Np. http://warszawa.gumtree.pl/c-PopularSearches
ulow
Indekser zapisuje w bazie/pamięci/gdzie chcesz pojedyncze słowa, ich ilość i miejsce występowania na stronie.

Co do popularności wyszukiwania, strona którą podałeś robi to na podstawie 1/2 słów. Można stworzyć tabelę w bazie i przy wyszukiwaniu sprawdzać czy takie słowo już w tej tabeli jest. Jeżeli nie ma: dodajesz je i ustawiasz wartość na 1, jeżeli już jest: zwiększasz ostatnią wartość o 1 i potem listujesz od największej do najmniejszej
Wave
Cytat(ulow @ 29.06.2010, 14:57:41 ) *
Co do popularności wyszukiwania, strona którą podałeś robi to na podstawie 1/2 słów. Można stworzyć tabelę w bazie i przy wyszukiwaniu sprawdzać czy takie słowo już w tej tabeli jest. Jeżeli nie ma: dodajesz je i ustawiasz wartość na 1, jeżeli już jest: zwiększasz ostatnią wartość o 1 i potem listujesz od największej do najmniejszej

nie brzmi zbyt wydajnie i bezpiecznie dla bazy ale wydaje się jedynym sposobem. Co rozumiesz przez 1/2 słów?
ulow
chodziło o "na podstawie jednego do dwóch słów" smile.gif
gothye
podobne rozwiązanie wykorzystane jest w silniku forum phpbb3 , nazywanie native text
Sedziwoj
Cytat(Mikz @ 25.06.2010, 18:03:41 ) *
Sedziwoj, nie jestem przekonany co do tego co mówisz. Znaczy oczywiście nie pozbywamy się obciążającego LIKE'a, ale można zrobić relację many-to-many zamiast takiej dziwnej kolumny z separatorami | i przy ponownym wyszukiwaniu takim zapytaniem z LIKE określić w WHERE tylko te rekordy których czas utworzenia lub modyfikacji jest późniejszy niż czas utworzenia rekordu wyszukiwania. To tak bez wdawania się w niepotrzebne szczegóły.
Za to problem który widzę to dodatkowe obciążenie bazy przy zapisywaniu wyników wyszukiwania, literówki popełnione przez wyszukujących i tak dalej

pawel_ - dzięki za ten skrypt, a właściwie za metodę z tymi słownikami smile.gif


Odnośnie budowania indeksu słów, takie rozwiązanie stosuje np. phpBB.


Ogólnie ta kreska | miała oznaczać rozdzielenie nazw kolumn, nie łączenie stringa.
Zresztą po latach wracając do tematu wiem że korzysta się z FTS, czy to tsearch2 w Postgresql <8.3 (od 8.3 rozszerzenie dołączyło do rdzenia bazy), czy to FTS w MySQL, czy Lucene (to jest sposób indeksowania, kody do obsługi są w różnych językach i pracują na jednym indeksie plikowym, bardzo fajne, tylko jak 2lata temu testowałem to wydajność kodu w PHP była żenująca, ale w java to śmigało jak głupie).
mankowski
Witam,
A ma ktos moze jakis tutorial do sphinxa, najlepiej z przykladami? Cos innego nic dokumentacja i forum na stronie sphinxa?
Ormin
Taka jeszcze krotka piłka - Sphinx czy Lucene i dlaczego?
Hellz
http://webhosting.pl/Sphinx.zbuduj.wlasna.wyszukiwarke.w.PHP

Z tego korzystałem, poznając Sphinxa. Do Lucyny znalazłem słabszą dokumentację i w projekcie postawiłem na Sphinxa. Jego główną zaletą jest możliwość postawienia jako osobny silnik do MySQL (przynajmniej tak to widzi PHP) - w zasadzie bez większych zmian w kodzie można cieszyć się wydajnym wyszukiwaniem korzystając z ORM. Testowana wydajność - przy kilkudziesięciu milionach rekordów znajdował żądaną informację w 0.0x s dla wyrazu i 0.x s dla frazy. Korzystam z wersji 2. Docelowo Sphinx ma ewoluować w stronę silnika bazy danych dedykowanego do szukania tekstowego i to jego niewątpliwy plus.
darko
Polecam Apache Solr oparty o Lucene. Łatwe, szybkie i przyjemne, konfiguracja xmlowa. Integrowałem z Magento dla średnio obciążonych sieci sklepów, działa miodzio i obsługuje niemal większość języków w tym chiński uproszczony. Polecam
mrWodoo
Ja zadam inne (banalne) pytanie.
Na czym polega wyszukiwarka z indeksowaniem?
Mam np tabelę
search_index i tam
word_id | word | article

Następnie dodając artykuł do bazy, tworzę indeks jego treści wyciągając np wyrazy dłuższe niż 3 znaki, do bazy wpisuję słowo (word) i do jakiego artykułu przynależy (article)?
marcio
Czy nie chodzi ci o cos takiego: http://www.beldzio.com/czy-chodzilo-ci-o-%...6-czyli-n-gramy
mrWodoo
Nie, nie chodziło mi o podpowiedzi, tylko jak się współcześnie tworzy wyszukiwarki, bo na pewno nie na LIKE (chociaż niektórzy nadal tego używają), googlujac doszedłem do wniosku, że używa się indeksów, ale jak?
marcio
Cytat(mrWodoo @ 31.03.2012, 21:25:28 ) *
Nie, nie chodziło mi o podpowiedzi, tylko jak się współcześnie tworzy wyszukiwarki, bo na pewno nie na LIKE (chociaż niektórzy nadal tego używają), googlujac doszedłem do wniosku, że używa się indeksów, ale jak?

Tam nie uzywa sie Like i nie chodzi tez o podpowiedzi jesli sie nie myle, poczytaj o full text i o wyszukiwaniu na podstawie tagow to tez jest ciekawe...
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2019 Invision Power Services, Inc.