Introduction to Solr
NKHumphreys
What is Solr
"Solr is an open source enterprise search platform from the Apache Lucene project. its major features include full-text search, hit highlighting, faceted search..." - Wikipedia
It is written in Java, and runs as a standalone server within a servlet (we use Tomcat)
What Solr is not
It is not a scraper.
It will index what you pass to it but it will not scrape the content from your site or your database.
There are various packages and libraries that will do this for you.
Alternatively, you can write your own site spider and while you are at it, I think the world is in need of a circular shaped item for the front of wheel barrows.
Quick overview of Solr
- Define the contents of the documents you want to be searchable (Schema) e.g. Product name, description, price etc...
- Deploy Solr to your application server
- Pass Solr the documents you want to be searchable (index)
- Expose search functionality in your application
Solr queries are RESTful and the responses can be in either XML, JSON or CSV
Solr also supports replication
What you need to know before you start...
Before you start implementing your schema:
- Talk to you PM and understand the clients search requirements
- Agree your search criteria and get some examples of desired results
- Get to know the data you are indexing and searching
- Provide your PM with your intended implementation (description of the schema)
- And finally, after the initial setup is done, provide your PM with an interface where they can test the search (talk to DD about exposing the admin interface to our sub-domain)
Schema
Solr schema tells Solr what your data is going to look like and how to treat each element of your data
e.g
<field name="title" type="text_en" stored="true" indexed="true" />
This tells Solr to treat the title attribute as type text_en. It also tells Solr that the field should be retrievable during search (stored) and it should itself be searchable (indexed)
Schema... how to treat data types
We can then tell Solr how to treat a data type during indexing, This is called an Analyzer:
<fieldType name="text_en" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.WhiteSpaceTokenizerFactory" />
<filter class=solr.LowerCaseFilterFactory />
</analyzer>
The text field will be passed through the "pipe" of tokenizers and filters...Schema... how to treat data types
We can also tell Solr how to treat data types during a query:
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory" />
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
<filter class="solr.LowerCaseFilterFactory" />
</analyzer>
</fieldType>
Again, the query text input will be passed through a "pipe" of tokenizers and filters...
Tokenizers
A Tokenizer breaks text up into a stream of tokens. A token is usually a subset of the characters in the text input.
Tokens also contain meta data, such as where in the text the token value occurs.
e.g.
<analyzer>
<tokenizer class="solr.WhitespaceTokenizerFactory" />
</analyzer>
This creates tokens of characters separated by whitespace
Filters
Like Tokenizers, filters take an input and produce a stream of tokens. However, a Filter's input is also a token stream. This input can come from either a Tokenizer or another Filter.
e.g.
<analyzer>
<tokenizer class="solr.WhitespaceTokenizerFactory" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.EnglishPorterFilterFactory" />
</analyzer>
This first breaks the text up into a stream of tokens separated by white space, then indexes the data in lower case, and finally applies standard English stemming to each token (more on this later).Putting it all together
<fieldType>
<analyzer type="index">
<tokenizer>
<filter>
</analyzer>
<analyzer type="query">
<tokenizer>
<filter>
</analyzer>
</fieldType>
You can have one of these for each fieldType you defineThe result of applying the tokenizers and filters is Solr storing or searching the data using several forms of the input e.g. if a user searches for "Murdering", Solr will also perform the search "Murder" and "murder" and return matches.
Some useful filters and tokenizers
- WhitespaceTokenizerFactory
- ApostropheFilterFactory
- LowerCaseFilterFactory
- StopFilterFactory
- SynonymFilterFactory
- PorterStemFilterFactory
For a list of tokenizers and filters and what they do, see:
https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters
Stopwords and Synonyms
You can supply a stopwords.txt and a synonyms.txt
When the StopFilterFactory is applied to an analyzer, any words in the stopwords.txt will be removed from the query
When the SynonymFilterFactory is applied to an analyzer, any words in the synonyms.txt will be replaced by the value in the synonyms.txt
synonyms.txt
i-pod, i pod => ipod
# multiple instances are merged
foo => foo bar
foo => baz
# is equivelent to
foo => foo bar, baz
Copy Fields
Another useful feature of the Solr schema is "copy fields". These fields tell Solr to take a copy of the original field, before tokenizers and filters are applied and store it, so that you may interpret the field in more than one way (different types -> different tokenizers and filters applied).
A good example of copy field usage, is storing the title field for sorting
<field name="title_sort" type="string" stored="true" indexed="true"/>
<copyField source="title" dest="title_sort"/>
This copies what is in the title field (which had type "text_en") and stores it in a field called title_sort (which has type "string"). This is because the string type is sortable.Solr Config
In the solrconfig.xml we can specify the parameters for configuring Solr
As well as default parameter configuration, you can define Request Handlers in this file.
Request Handlers
A request handler defines the logic executed for any request as well as default parameters for the search
<requestHandler name="/selectSimple" class="solr.SearchHandler">
<lst name="defaults">
<str name="wt">json</str>
<str name="defType">edismax</str>
<str name="fl">product_id,score</str>
<str name="qf">author^10 title^10 search_text</str>
<str name="bf">availability^15 scale(rating,0,100)</str>
<str name="sort">author, published_date</str>
<str name="pf">author^30 full_title^30 search_isbn^10</str>
<str name="facet.field">author</str>
<str name="f.author.facet.mincount">1</str>
</requestHandler>
This request handler can be accessed via the "name" parameter in the URLRequest Handlers...Cont
What do these parameters mean? Here are some of them...
- wt (writer type): which response type should be returned (XML, JSON, CSV)
- defType: specifies the query parser to use ( you should probably be using edismax - extended disjunction max)
- fl (field list): specifies which fields to return (limits the amount of information in the response)
- qf (query fields): list of fields, and the "boosts" to apply to them, when building the query (part of edismax, more on this later)
- bf (boost fields): functions with optional boosts that will be included in the query to influence the relevancy score
(more on boosts and relevancy later)
Request Handlers Cont...
To find out what the rest of the parameters mean, and how to use edismax, visit:
http://wiki.apache.org/solr/ExtendedDisMax
There are too many to go into in this talk
Lets look at the Solr interface
Facets
Faceted results are just results broken up into categories (often showing counts for each category).
These can be defined in the solrconfig.xml Request Handler definition.
<str name="facet.field">author</str>
The "author" field must exists in the schema
A facet query parameter (fq) can then be passed in the query URL
Facets...Cont
For example:
We could index the author of books using a copy field of type solr.StringField
e.g. Tolkien, Rowling etc...
Then when a user searches for a term e.g. "Fantasy" and clicks on a category (facet) to drill down on an author e.g. "Tolkien" we can reissue the query with a fq parameter e.g.
fq=author:"Tolkien"
This will only return results in that facet.The copy fields and facets must already exist in the schema and config.
BOOSTING
Field Boosting
The default order in which results are returned from Solr is "Relevancy". You can boost a fields contribution to the relevancy score using the following syntax (you should be using eDisMax, coming up in a few slides)
This takes the score for author, and boosts the result by 15. The boost is additive, so 15 is added to the relevancy score.<str name="bf">author^15 title^10</str>
This code is placed in the Solr config for a request handler.
Field Boosting Cont...
So if a query for the word "Tolkien" is performed, and one result has token in the "author" field, and the another result has "Tolkien" in the description field, the first result will appear first in the results
You can also use a multiplicative boost
<str name="boost">author^15 description^2</str>
A word of warning: Using a multiplicative boost with a large boost value can render all other relevancy contributions redundant. Getting the relevancy score correct is a bit of a dark art, and requires a bit of careful planning and a lot of trial and error.
Other Boost Functions
There are other boost functions other than additive and multiplicative. Some useful ones are:
- Scale: scales the relevancy scores relative to other relevancy scores so they appear between a min and max value.
- Pow: raises the relevancy to the supplied power
<str name="bf">scale(rating,0,100)</str>
For a full list of available functions see:
http://wiki.apache.org/solr/FunctionQuery
eDisMax
(Extended Disjunction Max)
This is a query parser with extended functionality.
It allows you to specify additional boosting queries and filtering queries. YOU SHOULD BE USING THIS!!
All of the eDisMax parameters can be specified in the SolrConfig or overridden using GET parameters in the request URL
eDisMax Cont...
All of the query parameters/attributes you have seen in these slides are available when using eDisMax (even if they are not specific to eDisMax)
Have I said that YOU SHOULD BE USING IT?
Committing data to the Solr Index
Once you have scraped the data from your site, and put it into the format that your Solr Schema is expecting, you can pass it the data as a JSON GET parameter to:
<solr_url>/solr/<core>update?commit=true
e.g.
curl 'http://localhost:5432/solr/default/update?commit=true' -H 'Content-type:application/json' -d '
[
{
"section": "detectives",
"title": "Sharkie and George",
"content": "Sharkie and George, crime busters of the sea, Sharkie and George, solve every mystery",
"link": "http://www.google.com",
"meta_bob": ["bob","bob2"]
}
]'
Don't forget the "commit=true"!!Delete the entire index
Sometimes it is useful to delete the entire index and re-index your data. To delete the entire index, simply use the following url in curl request:
curl http://<host>:<port>/solr/<core>/update?commit=true -d '<delete><query>*:*</query></delete>'
Here we are passing an xml document, the previous slide passed a JSON document, Solr can handle both.Gotchas
Some gotchas that we have found along the way:
- The NGramFilterFactory should probably never be used, it breaks the index/query text down in the chunks of a specified size and searches against them. e.g. "batteries would search for "bat", "ter" and "ies", if an ngram size of 3 is specified, which would have a positive match with "mysteries"....which is obviously wrong
- The cause of most mysterious search results seems to be boosting, what works for one query can cause drastic effects with other queries....test test test!
Gotchas Cont...
- The Solr Schema and Config are never finished, they are living documents and should be altered as your understanding of your data changes
SUMMARY
- The two most important files are your schema.xml and solrconfig.xml
- schema.xml describes what your data will look like and how to treat the incoming data from indexing and queries
- solrconfig.xml describes the default solr parameters and how to handle requests
- request handling parameters can be overridden in the request URL
- there are various tokenizers and filters you can apply to incoming data
- results can be faceted
-
USE EDISMAX!!
localhost:5432/solr/default/select?q=questions&fq=question_type="not-stupid"&wt=json
Introduction to Solr
By Nathan Humphreys
Introduction to Solr
Introduction to solr
- 840