Dzisiejszy wpis jest kolejnym z serii, w której staramy się przybliżyć funkcjonalności jakie pojawią się w wersji 4.0 Apache Solr. Dzisiaj przyjrzymy się funkcjonalności pozwalającej na zmianę sposobu w jaki zwracane są pola w dokumentach.
Po co mi taka funkcjonalność ?
Do tej pory, praktycznie, nie mieliśmy możliwości wpływania na to, jak budowane były odpowiedzi zwracane przez Solr. Wraz z pojawieniem się wersji 4.0 Solr dostaniemy do ręki nowe narzędzie, tzw. DocTransformers. Funkcjonalność ta pozwala na modyfikację pól w wynikach wyszukiwania zwróconych przez Solr. Patrząc na to, co w tym momencie jest dostępne, mamy na przykład możliwość zamiany nazw zwracanych pól, czy oznaczenia elementów dodawanych przez QueryElevationComponent. W tym momencie nie jest tego dużo, natomiast implementacja własnego DocTransformer’a nie jest trudna, o czym za chwilę.
Co jest już dostępne
W tym momencie, w wersji 4.0 Apache Solr dostępne są następujące funkcjonalności związane z DocTransformer’ami:
- Możliwość oznaczenia, które dokumenty zostały dodane przez QueryElevationComponent.
- Możliwość dodania informacji explain do dokumentu.
- Możliwość dodania stałej wartości jako pola do dokumentu.
- Możliwość dodania informacji o shardzie z jakiego pochodzi danych dokument.
- Możliwość dodania informacji docid jako pola dokumentu (identyfikator wykorzystywany przez Lucene).
Jak z tego skorzystać ?
Sprawdźmy, jak wygląda wykorzystanie tej funkcjonalności. Do tego celu pobrałem najnowszą wersję Apache Solr z repozytorium i uruchomiłem przykładowe wdrożenie. Następnie zaindeksowałem przykładowe dane i zadałem następujące zapytanie:
http://localhost:8983/solr/select?q=encoded&fl=name,score,[docid],[explain]
W powyższym zapytaniu warto przyjrzeć się parametrowi fl. Oprócz informacji takich, jak pole name oraz wartość score powiedzieliśmy Solr, że chcemy, aby do wygenerowania wyników wyszukiwania zostały wykorzystane dwa DocTransformery: [docid] oraz [explain]. W odpowiedzi Solr wygenerował następującego XML’a:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">2</int>
<lst name="params">
<str name="q">encoded</str>
<str name="fl">name,score,[docid],[explain]</str>
</lst>
</lst>
<result name="response" numFound="2" start="0" maxScore="0.50524884">
<doc>
<str name="name">Test with some GB18030 encoded characters</str>
<float name="score">0.50524884</float>
<int name="[docid]">0</int>
<str name="[explain]">
0.50524884 = (MATCH) weight(text:encoded in 0) [DefaultSimilarity], result of:
0.50524884 = score(doc=0,freq=1.0 = termFreq=1), product of:
1.0000001 = queryWeight, product of:
3.2335923 = idf(docFreq=2, maxDocs=28)
0.3092536 = queryNorm
0.5052488 = fieldWeight in 0, product of:
1.0 = tf(freq=1.0), with freq of:
1.0 = termFreq=1
3.2335923 = idf(docFreq=2, maxDocs=28)
0.15625 = fieldNorm(doc=0)
</str>
</doc>
<doc>
<str name="name">Test with some UTF-8 encoded characters</str>
<float name="score">0.4041991</float>
<int name="[docid]">25</int>
<str name="[explain]">
0.4041991 = (MATCH) weight(text:encoded in 25) [DefaultSimilarity], result of:
0.4041991 = score(doc=25,freq=1.0 = termFreq=1), product of:
1.0000001 = queryWeight, product of:
3.2335923 = idf(docFreq=2, maxDocs=28)
0.3092536 = queryNorm
0.40419903 = fieldWeight in 25, product of:
1.0 = tf(freq=1.0), with freq of:
1.0 = termFreq=1
3.2335923 = idf(docFreq=2, maxDocs=28)
0.125 = fieldNorm(doc=25)
</str>
</doc>
</result>
</response>
Jak widać, Solr dołączył do wyników wyszukiwania to o co go prosiliśmy.
Własna implementacja
Omówmy, jak wygląda implementacja własnego DocTransfomer’a. Poniżej, przykład klasy RenameFieldsTransformer z pakietu org.apache.solr.response.transform. Ogólnie polega to na implementacji następujących metod z klasy DocTransformer z pakietu org.apache.solr.response.transform:
String getName()– metoda zwracająca nazwę transformera,void transform(SolrDocument doc, int docid)– metoda dokonująca transformacji.
Sama implementacja wygląda następująco:
public class RenameFieldsTransformer extends DocTransformer {
final NamedList<String> rename;
public RenameFieldsTransformer( NamedList<String> rename ) {
this.rename = rename;
}
@Override
public String getName() {
StringBuilder str = new StringBuilder();
str.append( "Rename[" );
for( int i=0; i< rename.size(); i++ ) {
if( i > 0 ) {
str.append( "," );
}
str.append( rename.getName(i) ).append( ">>" ).append( rename.getVal( i ) );
}
str.append( "]" );
return str.toString();
}
@Override
public void transform(SolrDocument doc, int docid) {
for( int i=0; i<rename.size(); i++ ) {
Object v = doc.remove( rename.getName(i) );
if( v != null ) {
doc.setField(rename.getVal(i), v);
}
}
}
}
Powyższy kod umożliwia zwrócenie pola o innej nazwie, niż ta, która została zaindeksowana. Metoda transform iteruje po wszystkich wartościach zmiennej rename, która zawiera nazwę pól, które mają zostać zmienione wraz z nazwami na jakie powinny zostać zamienione. Należy pamiętać, iż, aby nasz własny transformer zaczął działać, należy dodać go do pliku solrconfig.xml. Oto przykład w wiki Solr:
<transformer name="elevated" class="org.apache.solr.response.transform.EditorialMarkerFactory" />
Podsumowując
Należy pamiętać, iż opisywana funkcjonalność jest oznaczona jako eksperymentalna i jej działanie może się zmienić w stosunku do opisywanego w chwili publikacji wersji 4.0 Solr i Lucene. Na pewno wrócimy do tematu po ukazaniu się Solr 4.0.