Pełnotekstowe wyszukiwanie w Pythonie z Solr i Lucene
28 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ą.
Info
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 Pythona
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')
<?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>
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