poniedziałek, 4 maja 2009

Lucynko gdzie są moje klucze cz. 2 - dbanie o indeks

W drugiej części postu na temat Zend_Search_Lucene miałem zamiar napisać na temat metod wyszukiwania dokumentów, jednak dostałem wiele zapytań na temat metod dbania o indeks (kasowania oraz edycji dokumentów), jak się okazuje nie jest to do końca proste zadanie, choć mam nadzieje, że po przeczytaniu tego wpisu okaże się to prostsze niż wyglądało na początku.


Na wstępie przypomnę, że Lucene nie ma możliwości aktualizacji dokumentów które są dodane do indeksu, żeby taką czynność wykonać należy dokument usunąć z indeksu i dodać go na nowo.

Aby indeks działał dobrze warto go porządnie zaprojektować, wystarczy trzymać się poniższej konwencji aby wszystko działało jak należy:
  1. wszystkie dane jakie chcecie wyszukiwać, ale nie macie zamiaru wyświetlać w wynikach wyszukiwania najlepiej trzymać w polach typu Unstored pozwoli to zaoszczędzić miejsca dla naszego indeksu, ta także przyśpieszy sam proces indeksowania i wyszukiwania
  2. dane które chcemy przeszukiwać, ale również wyświetlać należy przechowywać w polu typu Text, szczególnie jeśli są to duże partie tekstu
  3. jeśli to możliwe usuwajcie wszelkie html-owe tagi z dokumentu indeksowanego
  4. każdy dokument oznaczcie unikalnym identyfikatorem tworzonym według waszego algorytmu, tak abyście mogli łatwo zlokalizować taki dokument, identyfikator trzymajcie w polu typu Keyword

Najważniejszy jest ostatni podpunkt, dzięki niemu będziecie mogli sprawnie operować na indeksie, jak stworzyć taki identyfikator? Ja robię proste złączenie, biorę nazwę tabeli w bazie w której przechowywany jest rekord i łączę go z identyfikatorem rekordu, taki napis dodaję do indeksowanego dokumentu jako pole o nazwie doc i typie Keyword
$dokument->addField(Zend_Search_Lucene_Field::keyword('doc','artykul_'.$id));

Dzięki takiemu nazwaniu dokumentu nie muszę martwić się o dwa rekordy o tym samym id ale z różnych tabel, dodatkowo. Jeśli chcecie, możecie nazwę tabeli i rekord zapisać w oddzielnych polach np. doc_id, doc_name, dzięki temu będziecie w stanie usunąć wszystkie dokumenty pochodzące z zadanej tabeli.

Usuwanie dokumentów


Jeśli chodzi o samo usuwanie, to polega ono na znalezieniu dokumentu, oznaczeniu go do usunięcia, a następnie usunięciu. Niestety podczas budowania moich indeksów napotkałem się na dziwny błąd, a mianowicie wyszukiwarka nie potrafi poprawnie przeszukać pól typu Keyword z wykorzystaniem najprostszej metody wyszukującej $index->find();.

Rozwiązaniem tego problemu jest wykorzystanie wyszukiwania boolowskiego, dzięki niemu nasza wyszukiwarka jest w stanie znaleźć wartości w polach Keyword.

Kod który poprawnie wyszukuje nasz indeks wygląda następująco:
$term  = new Zend_Search_Lucene_Index_Term($entry, 'doc');
$queryTerm = new Zend_Search_Lucene_Search_Query_Term($term);
$finalQuery = new Zend_Search_Lucene_Search_Query_Boolean();
$finalQuery->addSubquery($queryTerm);
$search  = $index->find($finalQuery);
foreach($search AS $result){
$index->delete($result->id);
}
$index->commit();

A teraz linijka po linijce co się tam dzieje.
  1. Tworzymy wyrażenie dla indeksu, oraz wskazujemy w które pole ma być przeszukiwane
  2. Na podstawie utworzonego wyrażenia, tworzymy wyrażenie dla zapytania
  3. Tworzymy zapytanie boolowskie, to ono pozwoli nam poprawnie przeszukać pole typu keyword.
  4. Do zapytania boolowskiego podpinamy nasze zapytanie o konkretny dokument.
  5. Wykonujemy zapytanie
  6. Iterujemy po zwróconych wynikach (gdybyśmy np. szukali wszystkich artykułów)
  7. Każdy znaleziony dokument oznaczamy do usunięcia
  8. Potwierdzamy chęć usunięcia dokumentu

* Kod odpowiedzialny za otwarcie indeksu został pominięty

W ten sposób pozbędziemy się dokumentu który chcemy zaktualizować, po wykonaniu tych czynności możemy bez przeszkód dodać ponownie nasz dokument o czym było w poprzednim wpisie

1 komentarz:

  1. Lots of Good information in your posting, I bookmarked your blog post so I can visit again in the near future, Cheers :)

    OdpowiedzUsuń