Apache Solr 扩展 DisMax 参数的 Spring Data

Posted

技术标签:

【中文标题】Apache Solr 扩展 DisMax 参数的 Spring Data【英文标题】:Spring Data for Apache Solr Extended DisMax Parameters 【发布时间】:2017-03-16 18:51:22 【问题描述】:

我正在尝试在 Spring Data Solr 生成的 Solr 查询中添加以下参数 (qf,bq)。

Solr 参数为:

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

我找到了以下方法

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

我看到一个未解决的问题 qf https://jira.spring.io/browse/DATASOLR-153

如何将 qf 和 bq 参数添加到使用 Spring Data Solr 构建的 Solr 查询中。

谢谢

【问题讨论】:

【参考方案1】:

您可以在模板级别使用SolrCallback 访问SolrClient 并从那里执行查询,或者为自定义查询类型注册您自己的QueryParser

可能是这样的:

@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;
    

【讨论】:

我收到了这个错误:org.springframework.data.solr.core.QueryParserBase$NamedObjectsQuery cannot be cast to EdismaxQuery【参考方案2】:

Spring Data Solr API 4.0 有一些变化,因此您可能需要稍微更改一下注册自己的QueryParser 的方式。

@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;
    

这是使用新 EdismaxQuery 对象进行查询的方式

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);

【讨论】:

【参考方案3】:

为了避免:

org.springframework.data.solr.core.QueryParserBase$NamedObjectsQuery 无法转换为 EdismaxQuery

EdisMaxQueryParser 应该如下所示:

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

【讨论】:

【参考方案4】:

如果您要为每个选择查询添加静态 qf 表达式,可以在 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>

【讨论】:

【参考方案5】:

您可以将 edismax 库用于 spring-solr https://github.com/KmSYS/edismax-solr-spring

但是要克服在 afterPropertiesSet() 中覆盖已注册的查询解析器的问题,您需要在配置类中添加以下 bean,

    @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;
    

另外,https://github.com/KmSYS/edismax-solr-spring-sample 的示例代码

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

【讨论】:

以上是关于Apache Solr 扩展 DisMax 参数的 Spring Data的主要内容,如果未能解决你的问题,请参考以下文章

solr中使用了什么类型的解析器

solr 名称 关键字两个字段权重设置

全文搜索引擎技术详解之Apache Solr的使用

Apache Solr - 如何检查参数是不是输入正确?

全文搜索引擎技术详解之Apache Solr的使用

一文排查Apache Solr远程代码执行漏洞CVE-2019-12409