Data Import Handler – import danych z baz SQL (cz. 3)

W poprzednich odcinkach (cz. 1 i cz. 2) udało nam się zaimportować dane z bazy danych zarówno w sposób pełny, jak i przyrostowy. Dziś czas na małe podsumowanie.

Ustawienia dataSource

Przypomnijmy linię z naszej konfiguracji:

<dataSource
    driver="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/wikipedia"
    user="wikipedia"
    password="secret" />

To nie wszystkie atrybuty, które mogą się tutaj pojawić. Dla czytelności wypiszmy je wszystkie:

  • name – nazwa źródła – możemy zdefiniować wiele źródeł i odwoływać się do nich przez atrybut „dataSource” taga „entity”
  • driver – nazwa klasy sterownika jdbc
  • url – url jdbc do bazy danych
  • user – nazwa użytkownika bazy danych (jeśli nie zdefiniowany, lub pusty, połączenie do bazy następuje bez podania pary user/password)
  • password – hasło użytkownika
  • jndiName – zamiast podania elementów: driver/url/user/password można podać nazwę JNDI pod którą dostępna jest implementacja źródła danych (javax.sql.DataSource) udostępniana przez kontener (np. Jetty/Tomcat)

Argumenty zaawansowane:

  • batchSize (domyślnie: 500) – ustawia maksymalną liczbę (a raczej sugestię dla sterownika) rekordów pobieranych z bazy danych w jednym odwołaniu do bazy. Zmiana tego parametru może pomóc w sytuacji, gdy zapytania zwracają duże wyniki. Może też nie pomóc, gdyż implementacja tego mechanizmu zależy od sterownika JDBC.
  • convertType(domyślnie: false) – Wykonuje dodatkową konwersję z typu pola zwracanego przez bazę danych na typ pola zdefiniowanego w schema.xml. Domyślna wartość wydaje się być bezpieczniejsza, gdyż nie powoduje dodatkowych, magicznych konwersji. Jednak w szczególnych przypadkach (np. Pola typu BLOB) taka konwersja jest jednym ze sposobów rozwiązania problemu
  • maxRows (domyślnie: 0 – brak limitu) – ustawia maksymalną liczbę wyników zwracanych przez zapytania do bazy
  • readOnly – ustawia połączenie do bazy w tryb odczytu. W zasadzie może to oznaczać, że sterownik będzie mógł wykonać dodatkowe optymalizacje. Jednocześnie oznacza to domyślne(!) ustawienie transactionIsolation na TRANSACTION_READ_UNCOMMITTED, holdability na CLOSE_CURSORS_AT_COMMIT, autoCommit na true
  • autoCommit – ustawia automatyczne zatwierdzanie transakcji po każdym zapytaniu
  • transactionIsolation (TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE,TRANSACTION_NONE) – ustawia izolacje transakcji (czyli widoczność danych zmienionych w obrębie transakcji)
  • holdability (CLOSE_CURSORS_AT_COMMIT, HOLD_CURSORS_OVER_COMMIT)- definiuje sposób zamykania obiektów wyników (ResultSet) w sytuacji, gdy zamykana jest transakcja
  • – istotne jest to, że mogą wystąpić dowolne inne atrybuty. Wszystkie DIH przekazuje do drivera JDBC, co pozwala na definiowane specjalnych zachowań określonych przez konkretny driver JDBC.
  • type – typ źródła. Domyślna wartość (JdbcDataSource) jest wystarczająca, więc o tym tagu można zapomnieć (przypomnimy o nim sobie przy okazji definiowania nie-SQLowych źródeł)

Element „entity”

Przejdźmy teraz do opisu elementu „entity”.

Dla przypomnienia:

<entity name="page" query="SELECT page_id as id, page_title as name from page">
    <entity name="revision" query="select rev_id from revision where rev_page=${page.id}">
        <entity name="pagecontent" query="select old_text as text from pagecontent where old_id=${revision.rev_id}">
        </entity>
    </entity>
</entity>

I wszystkie atrybuty:

Podstawowe:

  • name – nazwa encji
  • query – zapytanie SQL służące do pobierania danych związanych z danym entity.
  • deltaQuery – zapytanie odpowiedzialne za zwrócenie identyfikatorów tych rekordów, które zmieniły się od ostatniego indeksowania (pełnego lub przyrostowego) – czas ostatniego indeksowania DIH dostarcza w zmiennej:${dataimporter.last_index_time}. To zapytanie jest używane przez SOLR do znajdowania tych rekordów, które się zmieniły.
  • parentDeltaQuery – zapytanie zwracające dane dla rekordu encji-rodzica. Dzięki tym zapytaniom SOLR jest w stanie pobrać wszystkie dane składające się na dokument, niezależnie od tego, z której encji pochodzą. Konieczne jest to dlatego, że silnik indeksowania nie ma możliwości modyfikacji zindeksowanych danych – musimy więc zindeksować cały dokument, niezależnie od tego, że część danych się nie zmieniła.
  • deletedPkQuery – dostarcza identyfikatorów usuniętych elementów.
  • deltaImportQuery – zapytanie zwracające dane dla rekordu o identyfikatorze podanym jako zmienna DIH: ${dataimport.delta.id}.
  • dataSource – nazwa źródła, wykorzystywana w przypadku definicji kilku źródeł (patrz: dataSource.name)

i zaawansowane:

  • processor – domyślnie SQLEntityProcessor. Element, którego zadaniem jest dostarczenie ze źródła danych kolejnych elementów do indeksowania. W przypadku baz danych zwykle domyślna implementacja jest wystarczająca
  • transformer – dane pobrane ze źródła mogą być dodatkowo modyfikowane przed przekazaniem do indeksowania. W szczególności transformer może zwracać dodatkowe rekordy, co powoduje, że jest to bardzo potężne narzędzie
  • rootEntity -domyślnie true dlaelementu entity znajdującego się poniżej elementu document. Oznacza ten element, który jest traktowany, jako głowny, tzn on posłuży do tworzenia nowych elementów w indeksie
  • threads – liczba wątków używanych przy obsłudze elementu entity
  • onError (abort, skip, continue) – sposób reakcji na błędy: przerwanie działania (abort, domyślne zachowanie), zignorowanie dokumentu (skip), zignorowanie błędu (continue)
  • preImportDeleteQuery – używany zamiast „*:* do skasowania danych z indeksu. (Uwaga: zapytanie do indeksu, nie zapytanie bazodanowe) – ma sens tylko w głównym elemencie entity
  • postImportDeleteQuery – używane po pełnym imporcie. (podobnie jak preImportDeleteQuery zapytanie do indeksu) – ma sens tylko w głównym elemencie entity
  • pk – klucz główny (bazodanowy, nie mylić z unikalnym kluczem dokumentu) – ma znaczenie tylko w indeksowaniu przyrostowym, jeśli pozwalamy DIH zgadnąć deltaImportQuery na podstawie query

Powyżej pojawiło się słowo „zgadnąć”. DIH stara się usprawniać pracę, poprzez przyjmowanie sensownych wartości domyślnych. Na przykład, tak jak wspomniano powyżej, w trakcie importowania przyrostowego jest w stanie sam spróbować określić deltaImportQuery. Tak na prawdę było to jedyne zachowanie we wcześniejszych wersjach, zdano sobie jednak sprawę z tego, że tak wygenerowane zapytanie nie zawsze zadziała. Stąd sugeruje się jednak ostrożność i zasadę ograniczonego zaufania 🙂

Innym drobiazgiem jest możliwość pominięcia definicji pól: field w sytuacji, gdy nazwy kolumn zwracanych przez zapytanie odpowiadają nazwom pól w schema.xml.  (Ręka w górę: kto zauważył, że przypomniany powyżej przykład wykorzystania entity nie jest kopią z części drugiej, tylko korzysta z tego mechanizmu?)

Jeszcze innym przykładem na to, że DIH jest bardzo elastyczny jest zwrócenie uwagi na fakt, że mając konstrukcję typu:

${dataimporter.last_index_time}

jesteśmy w stanie napisać tak definicję pełnego importu, że w sytuacji, gdy był już przeprowadzany import, będzie się ona zachowała jak import przyrostowy! Chyba ta funkcjonalność „wyszła” trochę przez przypadek 🙂

This entry was posted on poniedziałek, Listopad 22nd, 2010 at 08:44 and is filed under Bez kategorii. 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.

5 komentarzy to “Data Import Handler – import danych z baz SQL (cz. 3)”

  1. Piotrek Says:

    Sorka, że nie na temat, ale fajny błąd macie: http://solr.pl/tag/poprawne-zapytania/

  2. negativ Says:

    Dzięki za informacje. Poprawione.

  3. dawka902 Says:

    Witam,
    Skonfigurowałem połączenie z SOLR i MSSQL 2008R2

    w zapytanie wstawiłem procedurę składowaną:

    Wszystko działa prawidłowo dane są importowane do SOLR około 600 tyś rekordów tylko podczas importu zakładany jest lock na bazę danych, co praktycznie uniemożliwia korzystanie z niej(lokowane są wszystkie table z których pobierane są dane)

    Czy jest jakiś na to sposób.

  4. negativ Says:

    Bez popatrzenia na konfigurację tylko zgaduję. Ponieważ nie widzę też kodu procedury to pierwsze co mi przychodzi do głowy, to czy ona nie lockuje tabeli?

  5. dawka902 Says:

    SELECT p.[ProductId] ,[Product],[Description],[Price],[CategoryId]

    (SELECT s.ShopSeo +’$’ + REPLACE(s.[Shop],’,’,’ ‚) +’,’
    FROM [dbo].[ShopProducts] sp WITH (NOLOCK)
    inner join dbo.[Shops] s WITH (NOLOCK) ON s.ShopId = sp.ShopId and s.IsActive =1
    where p.DeleteDate is null and sp.ProductId = p.ProductId and sp.DateTo is null and s.IsActive =1 and sp.Price > 0 AND p.DeleteDate is null AND CategoryId is not null
    order by sp.ShopId
    FOR XML PATH(”) ) as ShopsSQL

    FROM [dbo].[Products] p WITH (NOLOCK)
    left join Brands b WITH (NOLOCK) on b.BrandId = p.BrandId