Ibrahim
Ibrahim

Reputation: 83

Spring Data for Apache Solr Extended DisMax Parameters

I am trying to add the params below (qf,bq) in a Solr query generated by Spring Data Solr.

Solr parameters are :

qf => Spring Data Solr Method?
bq => Spring Data Solr Method?

I was able to find the methods below

fq => addFilterQuery
fl => addProjectionOnField
defType => setDefType
qt => setRequestHandler

I saw an open issue qf https://jira.spring.io/browse/DATASOLR-153

How can i add the qf and bq params to Solr query built with Spring Data Solr.

Thanks

Upvotes: 4

Views: 1692

Answers (5)

ahmed fcis
ahmed fcis

Reputation: 36

you can use edismax library for spring-solr https://github.com/KmSYS/edismax-solr-spring

But to overcome the problem of overwrite the registered query parsers at afterPropertiesSet() you need to add following bean at config class,

    @Bean
    public SolrTemplate solrTemplate(SolrClient client) {
        SolrTemplate template = new SolrTemplate(client) {

            @Override
            public void afterPropertiesSet() {
                super.afterPropertiesSet();
                registerQueryParser(SimpleEdismaxQuery.class, new EdisMaxQueryParser(new SimpleSolrMappingContext()));
            }
        };

        template.afterPropertiesSet();
        return template;
    }

Also, sample code at https://github.com/KmSYS/edismax-solr-spring-sample

http://www.kmsys.tech/solr/edixmax-query-parser-template.html

Upvotes: 0

Montri M
Montri M

Reputation: 1766

There're some changes in Spring Data Solr API 4.0, so you may need to change how you registered your own QueryParser a bit.

@Bean
public SolrTemplate solrTemplate(SolrClient client) {
    SolrTemplate template = new SolrTemplate(client);
    solrTemplate.registerQueryParser(EdismaxQuery.class, new EdisMaxQueryParser(new SimpleSolrMappingContext()));
    return template;
}

public static class EdismaxQuery extends SimpleQuery {
    private String defaultField;
    private String minimumShouldMatch;
    private String boostQuery;
    private String queryField;

    public EdismaxQuery(String queryString) {
        super(queryString);
    }
    //... typical getter/setter
}

public static class EdisMaxQueryParser extends QueryParserBase<AbstractQueryDecorator> {

    private final DefaultQueryParser defaultQueryParser;

    public EdisMaxQueryParser(MappingContext<? extends SolrPersistentEntity<?>, SolrPersistentProperty> mappingContext) {
        super(mappingContext);
        defaultQueryParser = new DefaultQueryParser(mappingContext);
    }

    @Override
    public SolrQuery doConstructSolrQuery(AbstractQueryDecorator queryDecorator, Class<?> domainType) {
        // for some reason the API wrapped our query object with NamedObjectsQuery, so we need to unwrapped/get our actual query object first
        EdismaxQuery query = (EdismaxQuery) queryDecorator.getDecoratedQuery();

        // use defaultQueryParser to populate basic query parameters
        SolrQuery solrQuery = defaultQueryParser.doConstructSolrQuery(query, domainType);

        // set our own 'extra' parameter
        if (query.getDefaultField() != null) { 
            solrQuery.add("df", query.getDefaultField());
        }
        if (query.getMinimumShouldMatch() != null) {
            solrQuery.add("mm", query.getMinimumShouldMatch());
        }
        if (query.getQueryField() != null) {
            solrQuery.add("qf", query.getQueryField());
        }
        if (query.getBoostQuery() != null) {
            solrQuery.add("bq", query.getBoostQuery());
        }
        //...

        return target;
    }
}

Here's how you query with new EdismaxQuery object

EdismaxQuery query = new EdismaxQuery("hello world");
query.setDefType("edismax");
query.setRows(3);
query.setQueryField("text^2");
query.setMinimumShouldMatch("30%");
query.setBoostQuery("date:[NOW/DAY-1YEAR TO NOW/DAY]");

Page<ResultBean> results = solrTemplate.query("collection", query, ResultBean.class);

Upvotes: 2

Alex Rewa
Alex Rewa

Reputation: 318

If you are going to add static qf expression to each select query it could be done in solrconfig.xml:

<requestHandler name="/select" class="solr.SearchHandler">
<lst name="defaults">
  ...
</lst>
<lst name="appends">
  <str name="defType">edismax</str>
  <str name="qf">offerId^100 vendorCode^100</str>
</lst>
...
</requestHandler>

Upvotes: 0

In order to avoid:

org.springframework.data.solr.core.QueryParserBase$NamedObjectsQuery cannot be cast to EdismaxQuery

EdisMaxQueryParser should look like this:

class EdisMaxQueryParser extends QueryParserBase {
    @Override
    public SolrQuery doConstructSolrQuery(SolrDataQuery source) {
        // your stuff
    }
}

Upvotes: 0

Christoph Strobl
Christoph Strobl

Reputation: 6736

You can use the SolrCallback on template level to access the SolrClient and execute the query from there or register your own QueryParser for a custom query type.

Maybe something like:

@Bean
public SolrTemplate solrTemplate(SolrClient client) {

    SolrTemplate template = new SolrTemplate(client);
    template.registerQueryParser(EdismaxQuery.class, new EdisMaxQueryParser());
    return template;
}

class EdismaxQuery extends SimpleQuery {
    // ... add stuff you need. Maybe `autoRelax`
}

class EdisMaxQueryParser extends QueryParserBase<EdismaxQuery> {

    DefaultQueryParser defaultQueryParser = new DefaultQueryParser();

    @Override
    public SolrQuery doConstructSolrQuery(EdismaxQuery source) {

        // just use the default parser to construct the query string in first place.
        SolrQuery target = defaultQueryParser.constructSolrQuery(source);

        // add missing parameters
        target.add("defType", "edismax");
        target.add("qf", source....);

        return target;
    }
}

Upvotes: 3

Related Questions