I'm using Solr with Magento Enterprise. I'm trying to change the default search operator from OR
to AND
to make searches more specific by default.
The first thing I tried was to to change defaultOperator
in schema.xml
which did not have the desired effect (it started using AND
between fields, not keywords).
<solrQueryParser defaultOperator="AND"/>
I then read about LocalParams and tried adding that to several requestHandler
sections in solrconfig.xml
(I'm just guessing where it's supposed to go, I can't find any helpful documentation).
<requestHandler name="magento_en" class="solr.SearchHandler">
<lst name="defaults">
<str name="q.op">AND</str>
I also poked around in the code (app/core/core/Enterprise/Search
), hard-coded {!q.op=AND}
to the queries but still couldn't get it to work.
I imagine it's a simple configuration change, can anyone point me in the right direction?
Edit: To clarify, a search for "red jacket" (without quotes) should return results for "red AND jacket". I'm only interested in products that are actually red jackets, not red shoes and/or blue jackets. A manual search for "red AND jacket" returns the results that I'm after.
Currently a search performs these queries:
INFO: [] webapp=/solr path=/select params={start=0&q=articles_title:red+jacket*+articles_summary:red+jacket*+articles_text:red+jacket*+cms_title:red+jacket*+cms_content:red+jacket*&json.nl=map&wt=json&fq=store_id:1+store_id:0&version=1.2&rows=4} hits=7 status=0 QTime=1
09/01/2013 10:46:21 AM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/select params={spellcheck=true&sort=attr_sort_score_en+desc&spellcheck.extendedResults=true&json.nl=map&wt=json&spellcheck.collate=true&version=1.2&rows=1&fl=id&start=0&q=(Red+jacket)&spellcheck.dictionary=magento_spell_en&q.op=AND&spellcheck.count=2&qt=magento_en&fq=(visibility:3+OR+visibility:4)+AND+store_id:1} hits=645 status=0 QTime=5
09/01/2013 10:46:21 AM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/select params={facet=on&sort=score+desc&json.nl=map&wt=json&version=1.2&rows=24&fl=id&start=0&facet.query=category_ids:8&facet.query=category_ids:46&facet.query=category_ids:88&facet.query=category_ids:126&facet.query=category_ids:168&facet.query=category_ids:180&facet.query=category_ids:207&facet.query=category_ids:224&facet.query=category_ids:242&facet.query=category_ids:276&q=(Red+jacket)&q.op=AND&facet.field=attr_nav_multi_colourway&qt=magento_en&fq=(visibility:3+OR+visibility:4)+AND+store_id:1} hits=645 status=0 QTime=5
09/01/2013 10:46:22 AM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/select params={facet=on&sort=attr_sort_score_en+desc&json.nl=map&wt=json&rows=100&version=1.2&start=0&facet.query=category_ids:8&facet.query=category_ids:46&facet.query=category_ids:88&facet.query=category_ids:126&facet.query=category_ids:168&facet.query=category_ids:180&facet.query=category_ids:207&facet.query=category_ids:224&facet.query=category_ids:242&facet.query=category_ids:276&q=(Red+jacket)&q.op=AND&facet.field=attr_nav_multi_colourway&qt=magento_en&fq=(visibility:3+OR+visibility:4)+AND+store_id:1} hits=645 status=0 QTime=6
09/01/2013 10:46:22 AM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/select params={facet=on&sort=attr_sort_score_en+desc&json.nl=map&wt=json&rows=100&version=1.2&start=0&facet.query=category_ids:8&facet.query=category_ids:46&facet.query=category_ids:88&facet.query=category_ids:126&facet.query=category_ids:168&facet.query=category_ids:180&facet.query=category_ids:207&facet.query=category_ids:224&facet.query=category_ids:242&facet.query=category_ids:276&q=(Red+jacket)&q.op=AND&facet.field=attr_nav_multi_colourway&qt=magento_en&fq=(visibility:3+OR+visibility:4)+AND+store_id:1} hits=645 status=0 QTime=3
I ended up using q.op which changed the operator to AND instead of OR. For example:
Thanks to Macilias' link on the dismax parser plugin I've found a way to accomplish this with the settings in the solrconfig.xml. In this file there are requestHandler nodes for a bunch of different languages. I modified the english one since our store is in english. By default the xml looked like this:
The important parameter here is "mm" which stands for Minimum 'Should' Match. The dismax parser uses this instead of a default operator to determine how multiple search terms should be handled. A value of 1 means only one term from the query must match (same behavior as OR). A value of 100% mean all the terms must match (same behavior as AND). More complex values can be used as well. Follow the link above for more info. After changing settings in the solrconfig.xml file you'll need to restart the Solr server before they take effect.
This video is also a good Magento Solr resource: http://www.youtube.com/watch?v=07uIJSXdqpU They talk about Minimum Match around the 24 minute mark.
In solr you should use the dismax (or edismax) parser plugin. Here you can set the minimum should match to 100%. you can find more information here
To answer your question, I am quite sure that we need to specify the default operator for solrQueryParser in schema.xml and not in solrconfig.xml. As you mentioned, it is given as,
The reason why you did not get expected results may be because of the following reason:
If your search URL is something like,
Then what happens is, "red" is searched against field "articles_summary" but "jacket" is searched against your default search field (say "text") which if I am right will be a copy field containing copy of all searchable fields. Hence you will get a match for "red" in "articles_summary" and "jacket" in "text".
To get what you expect, I suggest you use something like following URL after setting default operation to AND as you already did:
If you have multiple fields to search, you may have to do like this:
Try the following (untested):
and the rest of the fields are used in a similar fashion with
fq
parameter.The above will return all those records where all the mentioned fields contain term red and jacket. However, if you are required to return a record where atleast one field contains red AND jacket, then I suggest that you use a copyfield to map all those fields to a single field and then search against the copyfield type.
To answer my own question, I ended up overriding the
Enterprise_Search_Model_Adapter_HttpStream
model to injectAND
s into the search query. I added theprepareSearchConditions()
method fromEnterprise_Search_Model_Adapter_Solr_Abstract
:It doesn't play nice with other operators obviously but in my case it's good enough™ (at least for now). I'm still hoping to find a better solution though.