开发者

Solr Custom RequestHandler - injecting query parameters

开发者 https://www.devze.com 2023-03-09 20:58 出处:网络
Short question: I\'m looking for a way (java) to intercept a query to Solr and inject a few extra filtering parameters开发者_高级运维 provided by my business logic. What structures should I use?

Short question: I'm looking for a way (java) to intercept a query to Solr and inject a few extra filtering parameters开发者_高级运维 provided by my business logic. What structures should I use?

Context: First of all, a little confession: I'm such a rookie regarding Solr. For me, setting up a server, defining a schema, coding a functional indexmanager and afterwards actually seeing the server returning the right results - exactly as intended! - was already much of an achievement for itself. Yay me!

However I'm currently working in an enterprise project that requires a little more than that. Roughly speaking, the solr instance is to be queried by several thousands of users through the very same requestHandler, being that the documents returned are automatically filtered according to a user's permission level. For example, if both the user A and the super-user B tried the very same search parameters (even the very same url), the user B would get all of user A's files and then some more. In order to accomplish this the documents are already indexed with the necessary permission level information.

Well, with this in mind and making use of Solr's extensive documentation for newb developers I tried to come up with a simple custom requestHandler that overrides the handleRequest function in order to inject the necessary extra parameters in the SolrQueryRequest. All is fine and dandy - except that I never see any difference at all in the QueryResponse, the server rudely ignoring my little manipulation. After a couple of days searching the web without so much of a hint weather if this the best approach, finally decided to come up and bother the fine folks here at StackOverflow.

So, in short, my questions are:

  • Is this a correct approach? Are there other alternatives? I can already grasp some of Solr's concepts, but admittedly there is much lacking and its entirely possible that am missing something.

  • If so, after modifying the query parameters is there anything I should do to force the QueryResponse to be updated? As far as I can tell these are merely encapsulating http requests, and I fail to sniff anything querying the server after the modifications are made.

Thanks in advance and so very sorry for the long post!

UPDATE

After a lot of reading APIs and specially much trial and error I've managed to get a functional solution. However I still fail to understand much of Solr's internals, therefore would still appreciate some enlightening. Feel free to bash at will, am still very aware of my rookiness.

The relevant part of the solution is this function which is called from by overriden handleRequestBody:

private void SearchDocumentsTypeII(SolrDocumentList results,
        SolrIndexSearcher searcher, String q, 
        UserPermissions up, int ndocs, SolrQueryRequest req,
        Map<String, SchemaField> fields, Set<Integer> alreadyFound)
        throws IOException, ParseException {


         BooleanQuery bq = new BooleanQuery();
         String permLvl = "PermissionLevel:" + up.getPermissionLevel();
         QParser parser = QParser.getParser(permLvl, null, req);
         bq.add(parser.getQuery(), Occur.MUST);

         Filter filter = CachingWrapperFilter(new QueryWrapperFilter(bq));   

         QueryParser qp = new QueryParser(q, new StandardAnalyzer());
         Query query =  qp.parse(q);                        

         append (results, searcher.search(
          query, filter, 50).scoreDocs,
          alreadyFound, fields, new HashMap<String,Object>(), 0,
          searcher.getReader(), true);

}

Basically the search query is not modified in any way, and instead a filter is applied containing the PermissionLevel of the user. Even so, why doesn't the following alternative work? The search query works perfectly when applied in the standard requestHandler, while in this case it simply doesn't hit any document.

private void SearchDocumentsTypeII(SolrDocumentList results,
        SolrIndexSearcher searcher, String q, 
        UserPermissions up, int ndocs, SolrQueryRequest req,
        Map<String, SchemaField> fields, Set<Integer> alreadyFound)
        throws IOException, ParseException {

         String qFiltered = q + " AND " + "PermissionLevel:" + up.getPermissionLevel();                              

         QueryParser qp = new QueryParser(qFiltered, new StandardAnalyzer());
         Query query =  qp.parse(qFiltered);                        

         append (results, searcher.search(
          query, null, 50).scoreDocs,
          alreadyFound, fields, new HashMap<String,Object>(), 0,
          searcher.getReader(), true);

}


Good news: you don't need to write any code to do that, you just have to configure Solr properly. The superuser would hit the standard request handler while the regular user would hit another request handler (also a solr.StandardRequestHandler) configured with an invariant with the filter query you want to force upon them.

See also http://wiki.apache.org/solr/SolrRequestHandler


Oh well. As previously stated, the answer that worked for me. Feel free to comment or bash!

   private void SearchDocumentsTypeII(SolrDocumentList results,
            SolrIndexSearcher searcher, String q, 
            UserPermissions up, int ndocs, SolrQueryRequest req,
            Map<String, SchemaField> fields, Set<Integer> alreadyFound)
            throws IOException, ParseException {


             BooleanQuery bq = new BooleanQuery();
             String permLvl = "PermissionLevel:" + up.getPermissionLevel();
             QParser parser = QParser.getParser(permLvl, null, req);
             bq.add(parser.getQuery(), Occur.MUST);

             Filter filter = CachingWrapperFilter(new QueryWrapperFilter(bq));   

             QueryParser qp = new QueryParser(q, new StandardAnalyzer());
             Query query =  qp.parse(q);                        

             append (results, searcher.search(
              query, filter, 50).scoreDocs,
              alreadyFound, fields, new HashMap<String,Object>(), 0,
              searcher.getReader(), true);
        }


Take a look this solr wiki page it says we should first consider using Apache Manifold Framework, and if it doesn't suite your need, then write your own requestHandler


I had exact same requirement. In case anyone seeing this, here is my solution.

Request handler

public class SearchRequestHanlder extends SearchHandler {

  @Override
  public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
    var map = req.getParams();
    if (map instanceof MultiMapSolrParams) {
      MultiMapSolrParams m = (MultiMapSolrParams) map;
      MultiMapSolrParams.addParam("bq", "category:film^220", m.getMap());
    }
    super.handleRequestBody(req, rsp);
  }

  @Override
  public String getDescription() {
    return "Custom SearchRequestHanlder";
  }

}

solrconf.xml

<lib dir="/opt/solr/data/cores/movies/lib" regex=".*\.jar" />

<!-- Make sure following line is after existing default <requestHandler name="/select" -->
<requestHandler name="/select" class="com.solrplugin.SearchRequestHanlder" />
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号