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ą.
- 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
Wadą jest fakt iż to 100% Javy i wymaga serwera servletów i całej "infrastruktury" oprogramowania związanej z nią.
- 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/.
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>
Określamy pola nadając im nazwy, typ, a także dodatkowe parametry jak
indexed określające czy pole ma być indeksowane,
stored daje możliwość pobierania wartości danego pola w wynikach wyszukiwania.
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>
Zastąp całość:
<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>
Znajdź i usuń definicje starego schematu:
<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"/>
Zrestartuj serwer Solr.
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>
Oczywiście elementów ("doc") może być więcej niż jeden. Aktualizacja następuję w momencie wysłania dokumentu o istniejącej już w indeksie wartości unikalnego pola (zazwyczaj "id"). Dodatkowo by wszystkie zmiany "weszły w życie" należy wykonać operację wysyłając
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
Aby usunąć rekord należy wysłać POSTem pod /solr/update/ dane w postaci XML:
<delete>
<id>WARTOŚC</id>
</delete>
Gdzie id to pole o unikalnej wartości. Istnieje możliwość też kasowania dla różnych warunków, a nie pojedynczych rekordów.
Oto prosty skrypt dodający dane i wyszukujący frazy dla podanego wcześniej schematu:
from httplib import HTTPConnection
def add(item_id, title, description, text):
DATA = '''<add><doc>
<field name="id">%d</field>
<field name="title">%s</field>
<field name="description">%s</field>
<field name="text">%s</field>
</doc></add>
<commit/>''' % (item_id, title, description, text)
con = HTTPConnection('0.0.0.0:8983')
con.putrequest('POST', '/solr/update/')
con.putheader('content-length', str(len(DATA)))
con.putheader('content-type', 'text/xml; charset=UTF-8')
con.endheaders()
con.send(DATA)
r = con.getresponse()
if str(r.status) == '200':
print r.read()
else:
print r.status
print r.read()
def search(key):
con = HTTPConnection('0.0.0.0:8983')
con.putrequest('GET', '/solr/select?q=title:%s&start=0&rows=2&fl=id,title,description' % key)
con.endheaders()
con.send('')
r = con.getresponse()
if str(r.status) == '200':
print r.read()
else:
print r.status
print r.read()
add(1, 'Django search engine', 'blaaaa', 'text')
add(2, 'Google search', 'blaaa', 'text')
add(3, 'Solr fulltext search engine', 'blaaaa', 'text')
add(4, 'Car engine', 'blaaaa', 'text')
search('engine')
Wynik jego działania to:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">70</int></lst>
</response>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">2</int></lst>
</response>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">2</int></lst>
</response>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">3</int></lst>
</response>
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">77</int><lst name="params"><str name="fl">id,title,description</str><str name="start">0</str><str name="q">title:engine</str><str name="rows">2</str></lst></lst>
<result name="response" numFound="3" start="0">
<doc>
<str name="description">blaaaa</str>
<str name="id">4</str><str name="title">Car engine</str>
</doc>
<doc>
<str name="description">blaaaa</str>
<str name="id">1</str><str name="title">Django search engine</str>
</doc>
</result>
</response>
Enterprise search with PHP and Apache Solr
Search 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
- Dodany: 28.07.2008 przez riklaunim