Wraz z wersją 4.3 serwera wyszukiwania Apache Solr dostaliśmy bardzo długo oczekiwaną funkcjonalność – możliwość dzielenia części kolekcji kiedy korzystamy z wdrożenia opartego o SolrCloud. W tym wpisie chcieliśmy wypróbować nową funkcjonalność i zobaczyć jak działa. Do dzieła więc.
Kilka słów na początek
Wybór odpowiedniej liczby części z jakich będzie składała się nasza kolekcja był do tej pory jedną z niewiadomych, których wartość musieliśmy znać przed wdrożeniem. Kiedy tylko stworzyliśmy kolekcję nie mogliśmy zmienić liczby shardów z jakich się składa, mogliśmy dodawać tylko nowe repliki. Oczywiście niosło to za sobą konsekwencje – jeżeli nasze zalożenia nie były prawidłowe mogło się okazać, iż liczba shardów jest niewystarczająca. Mogliśmy wtedy tylko zalożyć nową kolekcję z inną konfiguracją, a następnie przeindeksować dane. Aż do chwili, kiedy pojawił się Apache Solr 4.3, a wraz z nim możliwość dzielenia na części stworzonej już kolekcji.
Mały klaster
W celu przetestowania nowej funkcjonalności postanowiłem uruchomić klaster składający się z jednej instancji Solr oraz z wbudowanym ZooKeeperem oraz przykładową kolekcją dostarczaną wraz z Solr. W tym celu użyłem następującej komendy:
java -Dbootstrap_confdir=./solr/collection1/conf -Dcollection.configName=collection1 -DzkRun -DnumShards=1 -DmaxShardsPerNode=2 -DreplicationFactor=1 -jar start.jar
Po uruchomieniu Solr widok klastra przedstawiał się następująco:
Testowe dane
Do testów potrzebne są także jakieś dane, postanowiłem więc skorzystać z przykładowych dostarczanych z Solr i uruchomić następujące polecenie w katalogu exampledocs:
java -jar post.jar *.xml
Liczbę zaindeksowanych dokumentów sprawdzić można wykonując następującą komendę:
curl 'http://localhost:8983/solr/collection1/select?q=*:*&rows=0'
Na którą Solr odpowiedział następująco:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">5</int> <lst name="params"> <str name="q">*:*</str> <str name="rows">0</str> </lst> </lst> <result name="response" numFound="32" start="0"> </result> </response>
Jak widać zaindeksowanych zostało dokładnie 32 dokumenty.
Podział shard’a
Spróbujmy zatem podzielić nasz pojedynczy shard, z którego składa się nasza kolekcja. W tym celu wykorzystamy API kolekcji i nową akcję o nazwie SPLITSHARD, która w podstawowej wersji przymuje dwa parametery – collection, czyli nazwę kolekcji na której chcemy wykonać operację oraz shard, czyli nazwę shard’a którego chcemy podzielić. W naszym wypadku komenda, która podzieli kolekcję jest następująca:
curl 'http://localhost:8983/solr/admin/collections?action=SPLITSHARD&collection=collection1&shard=shard1'
Po chwili, jeżeli wszystko przebiegło poprawnie, powinniśmy dostać od Solr odpowiedź informującą o przebiegu operacji podziału, wyglądającą mniej więcej tak:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">9220</int> </lst> <lst name="success"> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">6963</int> </lst> <str name="core">collection1_shard1_1_replica1</str> <str name="saved">/home/solr/4.3/solr/solr.xml</str> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">6977</int> </lst> <str name="core">collection1_shard1_0_replica1</str> <str name="saved">/home/solr/4.3/solr/solr.xml</str> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">9005</int> </lst> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">9006</int> </lst> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">103</int> </lst> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">1</int> </lst> <str name="core">collection1_shard1_1_replica1</str> <str name="status">EMPTY_BUFFER</str> </lst> <lst> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">1</int> </lst> <str name="core">collection1_shard1_0_replica1</str> <str name="status">EMPTY_BUFFER</str> </lst> </lst> </response>
Wygląd klastra po podziale
Po podziale nasz klaster wygląda następująco:
Jak widać powstały dwa nowe shardy, które teoretycznie powinny zawierać dokumenty z shard1 – część z dokumentów powinny trafić do części oznaczonej shard1_1, a część do shard1_0. Ponownie korzystając z panelu administarcyjnego Solr możemy sprawdzić odpowiednie core’y:
Shard1_1
Statystki cześci kolekcji oznaczonej jako Shard1_1 wyglądają następująco:
Shard1_0
Natomiast statystki cześci kolekcji oznaczonej jako Shard1_0 wyglądają następująco:
Jak widać z 32 dokumentów, które były dostępne w oryginalnej części kolekcji powstały dwie części kolekcji – jedna przechowująca 18 dokumentów, a druga przechowująca 14 dokumentów. Teoretycznie się zgadza 🙂
Porządki
Na sam koniec zostawiłem sobie porządki. Po pierwsze, aby dane w nowych shardach były widoczne musimy wysłać polecenie commit do naszej kolekcji, np w następujący sposób:
curl 'http://localhost:8983/solr/collection1/update' --data-binary '<commit/>' -H 'Content-type:application/xml'
Możemy także usunąć oryginalny shard z kolekcji, korzystając np. z panelu administracyjnego Solr lub też używając CoreAPI.
Ostatni test
Jako podsumowanie postanowiłem sprawdzić, czy na pewno dokumenty są dostępne w odpowiednich częściach kolekcji. W tym celu skorzystałem z następującego polecenia:
curl 'http://localhost:8983/solr/collection1/select?q=*:*&rows=100&fl=id,[shard]&indent=true'
Odpowiedź Solr na powyższe zapytanie była następująca:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">7</int> <lst name="params"> <str name="fl">id,[shard]</str> <str name="q">*:*</str> <str name="rows">100</str> </lst> </lst> <result name="response" numFound="32" start="0" maxScore="1.0"> <doc> <str name="id">GB18030TEST</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">IW-02</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">MA147LL/A</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">adata</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">asus</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">belkin</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">maxtor</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">TWINX2048-3200PRO</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">VS1GB400C3</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">VDBDB1A16</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">USD</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">GBP</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">3007WFP</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">EN7800GTX/2DHTV/256M</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_0_replica1/</str></doc> <doc> <str name="id">SP2514N</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">6H500F0</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">F8V7067-APL-KIT</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">apple</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">ati</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">canon</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">corsair</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">dell</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">samsung</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">viewsonic</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">EUR</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">NOK</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">VA902B</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">0579B002</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">9885A004</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">SOLR1000</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">UTF8TEST</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> <doc> <str name="id">100-435805</str> <str name="[shard]">192.168.56.1:8983/solr/collection1_shard1_1_replica1/</str></doc> </result> </response>
Jak widać dokumenty pochodzą z obu nowych shardów, czyli znów widać, że wszystko się zgadza. Do samego tematu podziału kolekcji na pewno jeszcze wrócimy.