Search code examples
searchsolrluceneedismaxsolr-query-syntax

Solr conditional query fields (qf)


Is it possible to define query fields in Solr based on certain conditions? For e.g. I've three fields text, title and product.The solr config definition:

<str name="qf">text^0.5 title^10.0 Product</str>

What I'm looking here is to include "product" as a searchable field only when certain condition is met, for e.g. if author:"Tom", then search in Product as well.

Is there a way to do that during query time using edismax ?

The alternate I've is to add the product information to either text or title of the document (where author=Tom) during index time so it'll be searchable. But, I'm trying to avoid this if possible.

Any pointers will be appreciated.

-Thanks


Solution

  • In order to search in different fields based on different conditions, there is a need to first search for that specific conditions, thus it is more or less the same as issuing multiple queries.


    That said, in case there is a need to do it as a one-time query (e.g. for out-of-the-box sorting/grouping/other solr features), the nested queries can be used.

    For defining two different conditions (as in the original question, but it can easily be extended with more OR clauses), the q parameter can receive following value:

    _query_:"{!edismax fq=$fq1 qf=$qf1 v=$condQuery}"
    OR
    _query_:"{!edismax fq=$fq2 qf=$qf2 v=$condQuery}"
    

    The query uses Parameter Dereferencing, so there is no need to manually escape any special characters before passing the parameters to solr.

    • fq1 - first special condition
    • qf1 - list of fields to search in for first special condition (fq1)
    • fq2 - second special condition
    • qf2 - list of fields to search in for first special condition (fq2)
    • condQuery - the actual search term/query

    The fq1 may be empty in order to define a baseline (in this particular case - search in text and title, but not in product).

    The raw parameters themselves will look the following way:

    fq1=&qf1=text^0.5 title^10.0&fq2=author:"Tom"&qf2=text^0.5 title^10.0 Product&condQuery=5
    

    And the Final query will be something like this:

    http://localhost:8983/solr/collection1/select?q=_query_%3A%22%7B!edismax+fq%3D%24fq1+qf%3D%24qf1+v%3D%24condQuery%7D%22+OR+_query_%3A%22%7B!edismax+fq%3D%24fq2+qf%3D%24qf2+v%3D%24condQuery%7D%22&fl=*%2Cscore&wt=xml&indent=true&fq1=&qf1=text^0.5%20title^10.0&fq2=author:%22Tom%22&qf2=text^0.5%20title^10.0%20Product&condQuery=5
    

    .. or the same query returned by solr in solr response (provided only for showing it in a structured way):

    <response>
        <lst name="responseHeader">
            <int name="status">0</int>
            <int name="QTime">1</int>
            <lst name="params">
                <str name="q">_query_:"{!edismax fq=$fq1 qf=$qf1 v=$condQuery}" OR _query_:"{!edismax fq=$fq2 qf=$qf2 v=$condQuery}"</str>
                <str name="condQuery">5</str>
                <str name="indent">true</str>
                <str name="fl">*,score</str>
                <str name="fq1"/>
                <str name="qf1">text^0.5 title^10.0</str>
                <str name="fq2">author:"Tom"</str>
                <str name="qf2">text^0.5 title^10.0 Product</str>
                <str name="wt">xml</str>
            </lst>
        </lst>
        <result name="response" numFound="..." start="..." maxScore="...">
            ...
        </result>
    </response>
    

    Even though it works, I suggest to consider the effect it would have on query time (as each condition will have a separate internal search query) and measure how it affects your specific case.