Pełnotekstowe wyszukiwanie w PHP z Solr i Lucene
29 July 2008
Comments
Solr to serwer pełnotekstowego wyszukiwania oparty o Lucene. Solr poprzez interfejs XML/JSON/HTTP umożliwia indeksowanie, wyszukiwanie, aktualizowanie i kasowanie danych. Zastosowana biblioteka Lucene zapewnia bogaty zestaw funkcjonalności. Zarówno Lucene jak i Solr napisane są w Javie, lecz niezależny od języka interfejs umożliwia korzystanie z serwera z poziomu praktycznie każdego języka programistycznego. Jeżeli rozwiązania takie jak Sphinx stają się zbyt "słabe" to Solr może okazać się dobrą alternatywą.
Zalety Solr
- Wieloplatformowy i łatwo dostępny (Java, REST)
- Aktywnie rozwijany (Apache Foundation)
- Replikacja, import CSV, obsługa synonimów, podświetlanie trafień
- Szybki i wydajny serwer
- Używany m.in. przez digg.com, wikipedię, sourceforge, gamespot
Instalacja i uruchomienie Solr
- By solr działał potrzebna jest zainstalowana wirtualna maszyna Javy
- Pobieramy najnowszą wersję Solr
- Rozpakuj archiwum i przjedź do apache-solr-*/example i wykonaj polecenie:
java -jar start.jar
- Jeżeli wszystkie zależności są spełnione i nie wystąpią nieoczekiwane problemy to serwer Solr zbudowany z serwerem Jetty powinien się uruchomić. Panel admin Solr powinien być dostępny pod adresem http://0.0.0.0:8983/solr/admin/.
Indeksowanie i wyszukiwanie
Schemat indeksu
Do tworzenia określonych indeksów Solr używa schematów określających strukturę i sposób obsługi indeksowanych danych. Oto przykład prostego schematu:<fields>
<field name="id" type="string" indexed="true" stored="true" required="true" />
<field name="title" type="text" indexed="true" stored="true"/>
<field name="description" type="text" indexed="true" stored="true"/>
<field name="text" type="text" indexed="true" stored="true"/>
</fields>
<uniqueKey>id</uniqueKey>
Edytuj solr/conf/schema.xml i znajdź:
<fields>
<!-- Valid attributes for fields:
name: mandatory - the name for the field
type: mandatory - the name of a previously defined type from the <types> section
indexed: true if this field should be indexed (searchable or sortable)
stored: true if this field should be retrievable
compressed: [false] if this field should be stored using gzip compression
(this will only apply if the field type is compressable; among
the standard field types, only TextField and StrField are)
multiValued: true if this field may contain multiple values per document
omitNorms: (expert) set to true to omit the norms associated with
this field (this disables length normalization and index-time
boosting for the field, and saves some memory). Only full-text
fields or fields that need an index-time boost need norms.
-->
.....
<uniqueKey>id</uniqueKey>
<fields>
<field name="id" type="string" indexed="true" stored="true" required="true" />
<field name="title" type="text" indexed="true" stored="true"/>
<field name="description" type="text" indexed="true" stored="true"/>
<field name="text" type="text" indexed="true" stored="true"/>
</fields>
<uniqueKey>id</uniqueKey>
<copyField source="id" dest="sku"/>
<copyField source="cat" dest="text"/>
<copyField source="name" dest="text"/>
<copyField source="name" dest="nameSort"/>
<copyField source="name" dest="alphaNameSort"/>
<copyField source="manu" dest="text"/>
<copyField source="features" dest="text"/>
<copyField source="includes" dest="text"/>
<copyField source="manu" dest="manu_exact"/>
Dodawanie i aktualizowanie danych
Aby dodać dane należy wysłać POSTem pod /solr/update/ dane w postaci XML:<add><doc>
<field name="nazwapola">wartość</field>
<field name="nazwapola">wartość</field>
<field name="nazwapola">wartość</field>
</doc></add>
<commit/>
Wyszukiwanie
By pobrać wyniki wyszukiwania należy wykonać żądanie GET adresu /solr/select z parametrami takimi jak:- q=NAZWA_POLA:SZUKANA_FRAZA - szukanie podanej frazy w danych z podanego pola
- fl=POLE1,POLE2,POLEn - jakie pola mają być zwrócone wraz z wynikami
Kasowanie rekordów z indeksu
Aby usunąć rekord należy wysłać POSTem pod /solr/update/ dane w postaci XML:<delete>
<id>WARTOŚC</id>
</delete>
Obsługa Solr z poziomu PHP
Dostępne jest już binarne rozszerzenie do obsługi Solr zapewniajace lepsze i wydajniejsze API.
Istnieje gotowa biblioteka obsługująca serwer Solr - ze strony projektu pobieramy SolrPhpClient.zip i rozpakowujemy go do pustego katalogu "Apache" tak by otrzymać ścieżkę Apache/Solr/Service.php. Biblioteka wymaga PHP5 (najlepiej 5.2.0, koniecznie z funkcją json_decode). Oto przegląd jej podstawowych możliwości.
<?php
require_once( 'Apache/Solr/Service.php' );
# łączymy się z serwerem
$solr = new Apache_Solr_Service( '0.0.0.0', '8983', '/solr' );
if ( ! $solr->ping() ) {
echo 'Solr nie odpowiada.';
exit;
}
#dodanie do indeksu
$parts = array(
'test1' => array(
'id' => 22,
'title' => 'Search engines',
'description' => 'Opis',
'text' => 'treść',
),
'test2' => array(
'id' => 21,
'title' => 'Searching a database',
'description' => 'Opis2',
'text' => 'treść2',
)
);
$documents = array();
foreach ( $parts as $item => $fields ) {
$part = new Apache_Solr_Document();
foreach ( $fields as $key => $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $datum ) {
$part->setMultiValue( $key, $datum );
}
}
else {
$part->$key = $value;
}
}
$documents[] = $part;
}
# przesłanie dokumentów do Solr
try {
$solr->addDocuments( $documents );
$solr->commit();
$solr->optimize();
}
catch ( Exception $e ) {
echo $e->getMessage();
}
# Wyszukiwanie
$offset = 0;
$limit = 10;
# szukamy frazy "search" w polu "title"
$queries = array(
'title: search'
);
foreach ( $queries as $query ) {
$response = $solr->search( $query, $offset, $limit );
if ( $response->getHttpStatus() == 200 ) {
// print_r( $response->getRawResponse() );
if ( $response->response->numFound > 0 ) {
echo '<h1>'.$query.'</h1>';
foreach ( $response->response->docs as $doc ) {
echo $doc->id.' - '.$doc->title.'<br />';
}
echo '<br />';
}
}
else {
echo $response->getHttpStatusMessage();
}
}
?>
W sieci
Enterprise search with PHP and Apache SolrSearch smarter with Apache Solr, Part 1: Essential features and the Solr schema
Search smarter with Apache Solr, Part 2: Solr for the enterprise
Prezentacje na slideshare
RkBlog
Comment article