在自定义SearchComponent中使用SolrParams覆盖Solr中的“fl”参数

时间:2011-12-05 23:14:57

标签: solr

我有一个有趣的用例,我们有一个Solr实现,其中在执行查询时不应返回Solr Schema中的某些字段。理想的解决方案是更改调用程序,使其不像现在一样查询&fl=score,只请求必要的字段,但这不会在短期内发生,所以在此期间我们必须过滤掉Solr响应中的一些字段。

我们认为对性能影响最小的方法(让我知道是否有更好的方法),是覆盖&fl=参数,以便列出所有字段,但应该过滤的字段出。为此,我们在RequestHandler组件列表中添加了一个新的SearchComponent,用于修改&fl参数。我们遇到的问题是,一旦我们从SolrParams获得SolrQueryRequest,它就无法修改(我认为这是正确的做法,因为它可能会改变另一个SearchComponent依赖于)。但是我们仍然需要找到一种方法来删除这些额外的字段。

所以,这是我们开始编写的代码:

public void prepare(ResponseBuilder rb) throws IOException {
        SolrQueryRequest req = rb.req;
        SolrParams params = req.getParams();
        String fl = params.get("fl");
        //Remove the "fl" parameter from params and replace it with a new list:
        //Cannot be done"
        ...

遇到了无法添加到SolrParams的问题。

作为计划B,同一个SearchComponent正在删除process()方法中的字段,但这样做的速度较慢。代码必须通过生成的SolrDocumentList,并为每个SolrDocument调用removeFields(),类似于:(简化代码)

public void process(ResponseBuilder rb) throws IOException {
    ...
    SolrQueryResponse rsp = rb.rsp;
    NamedList values = rsp.getValues();
    SolrDocumentList docs = (SolrDocumentList) values.get("response");
    Iterator<SolrDocument> docsIterator = sdoclist.iterator();
    while (docsIterator.hasNext()) {
        SolrDocument sd = sdocIterator.next();
        sd.removeFields(field);
        ...

关于如何实现这一目标的任何想法?

感谢您的任何建议!

2 个答案:

答案 0 :(得分:1)

使用您自己的SearchHandler,您可以在任何查询参数上指定不变量(无论请求总是会被修复的东西),其中包括&amp; fl。

这就是:

<requestHandler name="filtered" class="solr.StandardRequestHandler">
    <lst name="invariants">
      <str name="fl">score,id,something_else,etc.</bool>
    </lst>

  </requestHandler>

更多文档: http://wiki.apache.org/solr/SearchHandler

唯一的问题是,目前,没有负的fl参数(即返回除我告诉你的那些以外的所有字段)。 https://issues.apache.org/jira/browse/SOLR-3191

最后,要指定在查询时使用哪个SearchHandler,只需添加&amp; qt = filtered (或您使用的名称)

答案 1 :(得分:0)

尝试从ReturnFields对象中删除不需要的字段。 例如,像这样:

@Override
public void process(ResponseBuilder rb) throws IOException {
    String fl = rb.req.getParams().get(CommonParams.FL);
    List<String> fields = Lists.newArrayList(fl.split(","));
    List<String> newFields = Lists.newArrayList();
    for (String field : fields) {
        if (!field.equals("score")) {
            newFields.add(field);
        }
    }
    String newFl = Joiner.on(",").join(newFields);
    ReturnFields returnFields = new ReturnFields(newFl, rb.req);
    rb.rsp.setReturnFields(returnFields);
}

我在solrconfig.xml的“last-components”中设置了自定义SearchComponent

P.S:我在列表和Joiner中使用了番石榴库。