Solr 4.0: Aktualizacja pól dokumentów

Solr i Lucene 4.0 powoli zaczynają pojawiać się na horyzoncie i w związku z tym postanowiłem opisać kolejną funkcjonalność, która może okazać się przydatna wielu użytkownikom Solr – częściowa aktualizacja dokumentów.

Wersja Solr

W celu przetestowania funkcjonalności o której mowa we wpisie, skorzystałem z nadchodzącej dużymi krokami Apache Solr 4.0 alpha.

Założenia

Załóżmy, że potrzebujemy aktualizować jedno z pól w indeksie, ale tak, aby nie przesyłać ponownie całego dokumentu. Np. niech to będzie cena produktu, która aktualizowana jest kilkukrotnie w ciągu dnia. Nie chcemy, za każdym razem gdy zmieni się cena, aktualizować całego dokumentu, ponieważ każdy dokument to tak naprawdę nie tylko meta dane, ale także pliki binarne przetwarzane przez Tika, a tym samym takie indeksowanie jest dość czasochłonne. Co możemy w takim wypadku zrobić ? O tym za chwilę, zacznijmy od struktury indeksu.

Struktura indeksu

Struktura indeksu, jest bardzo prosta, zawiera pola odpowiadające za identyfikator produktu (id), jego nazwę (title), cenę (price) oraz opis (description). Fragment pliku schema.xml wygląda następująco:

<fields>
  <field name="id" type="string" indexed="true" stored="true" required="true" />
  <field name="name" type="text_general" indexed="true" stored="true"/>
  <field name="price" type="float" indexed="true" stored="true" />
  <field name="description" type="text_general" indexed="true" stored="true" />
  <field name="_version_" type="long" indexed="true" stored="true"/>
</fields>

Warto zauważyć dwie rzeczy: po pierwsze wszystkie pola oznaczone są jako stored=”true”. Dlaczego tak ? O tym trochę później. Druga rzecz to pole o nazwie _version_, które używane jest używane wewnętrznie przez Solr i jest konieczne.

Zawartość indeksu

Do testów zaindeksowałem jeden przykładowy dokument, który po zadaniu zapytania q=*:* prezentował się następująco:

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="name">Test 1</str>
    <float name="price">479.95</float>
    <str name="description">Description 1</str>
    <long name="_version_">1406418192301031424</long>
  </doc>
</result>
</response>

Częściowa aktualizacja

Aby zaktualizować cenę dokumentu, należy do Solr wysłać następujące polecenie:

curl 'localhost:8983/solr/update?commit=true' -H 'Content-type:application/json' -d '[{"id":"1","price":{"set":100}}]'

Powyższe polecenie mówi, że w dokumencie o polu id równym 1 należy zmienić pole price i ustawić je na wartość 100. Jak wygląda nasze zapytanie q=*:* po wysłaniu powyższego zapytania ? Wynik tego zapytania wygląda następująco:

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="name">Test 1</str>
    <float name="price">100.0</float>
    <str name="description">Description 1</str>
    <long name="_version_">1406418399028838400</long>
  </doc>
</result>
</response>

Jak widać pole price zostało uaktualnione. Zmieniła się także wartość pola _version_. Czyli dokładnie to, o co nam chodziło.

Co oprócz aktualizacji ?

Oprócz aktualizacji wartości pól w dokumentach funkcjonalność ta pozwala także na inne operacje, takie jak np. dodawanie wartości do pól wielowartościowych. Dla zainteresowanych polecam testy z komendą add (w odróżnieniu do przykładowego wykorzystania komendy set). Jak widać, nowa funkcjonalność Solr nie ogranicza się zaledwie do aktualizacji wartości pól, ale pozwala na trochę więcej operacji na dokumencie.

Rzeczy o których należy pamiętać

Wróćmy do struktury indeksu. Jak napisałem wcześniej, wszystkie pola w dokumencie ustawione są jako stored=”true”. Dzieje się tak dlatego, że tak naprawdę pojedyncze pole w indeksie nie jest uaktualniane, a uaktualniany jest cały dokument. Solr stosuje sztuczkę i pobiera pola, które oznaczone są jako stored=”true”, usuwa dokument, a następnie dodaje go ponownie, nanosząc na pobrane wartości zmiany, które kazaliśmy zrobić. Tylko tyle i aż tyle.

Podsumowanie

Obecna w Solr 4.0 funkcjonalność aktualizacji pól dokumentów nie aktualizuje pól w indeksie, a usuwa istniejący dokument indeksując w jego miejsce uaktualniony. Wszystko dzieje się po stronie Solr, a zatem jesteśmy zwolnieni z obowiązku martwienia się o aktualizację pojedynczego (bądź wielu) pól w dokumentach znajdujących się w indeksie. Oczywiście, musimy pogodzić się z większym indeksem, ze względu na to, że pola dokumentów muszą być przechowywane w oryginalnej postaci, bo inaczej Solr nie będzie w stanie ich odczytać. Zyskujemy zatem czas potrzebny na przetworzenie dokumentu i przesłanie go przez sieć, należy jednak pamiętać, iż cały proces indeksacji zostanie wykonany na nowo.

This entry was posted on poniedziałek, Lipiec 9th, 2012 at 07:58 and is filed under Indeksowanie, Solr. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

4 komentarze to “Solr 4.0: Aktualizacja pól dokumentów”

  1. tetete Says:

    A jak wygląda proces aktualizacji pól w sytuacji, gdy jedno/wiele pól jest kopiowanych przy użyciu instrukcji copy w schema.xml?

  2. gr0 Says:

    Nie sprawdzałem osobiście, ale wydaje mi się, że nie jest to żaden problem dla Solr. Należy pamiętać, że to co robi Solr, to tak naprawdę usuwa istniejący dokument, następnie dodaje ponownie już uaktualniony. W związku z tym wszystkie definicje copyField będą normalnie zastosowane, tak jak w przypadku dodawania nowego dokumentu.

  3. Plama Says:

    O Bogowie, szukałem tej informacji w całym internecie, tylko nie nazwałbym tego sztuczką, a dość sporym niedociągnięciem. Choć wierzę, że chęci mieli dobre 🙂

  4. gr0 Says:

    Fajnie, że można o tym u nas poczytać 😉