博客信息

修改solr的源码使用接口调用配置搜索竞价排名

发布时间:『 2016-11-28 00:18』  博客类别:Solr/ES  阅读(1865) 评论(0)

我们知道QueryElevationComponent组件可以实现竞价排名的功能,但是很不方便,需要在xml中配置。但大多数情况下,我们需要在我们的管理后台录入数据进行设置。

那么需求来了,可否我将竞价排名的数据录入数据库,使用接口让solr实时更新竞价排名的数据。经过研究源码,是可以实现的。只需要修改如下Handler即可:

org.apache.solr.handler.component.QueryElevationComponent

所以,我们下载solr的源码对该类进行修改,找到方法loadElevationMap修改为以下代码:

 //load up the elevation map
  private Map<String, ElevationObj> loadElevationMap(Config cfg) throws IOException {
    XPath xpath = XPathFactory.newInstance().newXPath();
    Map<String, ElevationObj> map = new HashMap<String, ElevationObj>();
    //第一步:计算elevate/query节点的配置
    NodeList nodes = (NodeList) cfg.evaluate("elevate/query", XPathConstants.NODESET);
    for (int i = 0; i < nodes.getLength(); i++) {
      Node node = nodes.item(i);
      String qstr = DOMUtil.getAttr(node, "text", "missing query 'text'");

      NodeList children = null;
      try {
        children = (NodeList) xpath.evaluate("doc", node, XPathConstants.NODESET);
      } catch (XPathExpressionException e) {
        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
            "query requires '<doc .../>' child");
      }
      
      ArrayList<String> include = new ArrayList<String>();
      ArrayList<String> exclude = new ArrayList<String>();
      for (int j = 0; j < children.getLength(); j++) {
        Node child = children.item(j);
        String id = DOMUtil.getAttr(child, "id", "missing 'id'");
        String e = DOMUtil.getAttr(child, EXCLUDE, null);
        if (e != null) {
          if (Boolean.valueOf(e)) {
            exclude.add(id);
            continue;
          }
        }
        include.add(id);
      }

      ElevationObj elev = new ElevationObj(qstr, include, exclude);
      if (map.containsKey(elev.analyzed)) {
        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
            "Boosting query defined twice for query: '" + elev.text + "' (" + elev.analyzed + "')");
      }
      map.put(elev.analyzed, elev);
    }
    //第二步:计算elevate/interface节点的配置,使用接口配置elevate
    nodes = (NodeList) cfg.evaluate("elevate/interface", XPathConstants.NODESET);
    NodeList urlNodes = null;
    Node node = null;
    Node urlNode = null;
    ObjectMapper objectMapper = new ObjectMapper();
    Map<String,Object> tempMap = null;
    List elevates = null;
    for (int i = 0; i < nodes.getLength(); i++) {
        ArrayList<String> include = new ArrayList<String>();
        ArrayList<String> exclude = new ArrayList<String>();      
        node = nodes.item(i);
        try {
          urlNodes = (NodeList) xpath.evaluate("url", node, XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
              "query requires '<url .../>' child");
        }
        for(int j = 0;j < urlNodes.getLength();j++){
            urlNode = urlNodes.item(j);
            String url = DOMUtil.getAttr(urlNode, "value", "missing 'value'");
            elevates = objectMapper.readValue(new URL(url), List.class);
            if(elevates != null && elevates.size() != 0){
                 int size = elevates.size(); 
                 for(int k = 0;k < size;k++){
                    tempMap = (Map<String,Object>)elevates.get(k);
                    String q = (String)tempMap.get("q");//关键词
                    ArrayList<String> ids = (ArrayList<String>)tempMap.get("ids");//需要排在前面的docId
                    ArrayList<String> eids = (ArrayList<String>)tempMap.get("eids");//需要排除在结果集外的docId
                    include.addAll(ids);
                    exclude.addAll(eids);
                    ElevationObj elev = new ElevationObj(q, include, exclude);
                    if (map.containsKey(elev.analyzed)) {
                      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                          "Boosting query defined twice for query: '" + elev.text + "' (" + elev.analyzed + "')");
                    }
                    map.put(elev.analyzed, elev);                      
                 }
            }
        }
    }
    //返回map
    return map;
  }

将编译后的class替换solr-core-xxx.jar中的class,即可。

在data目录新建elevate.xml,配置如下:

<elevate>

 <query text="tomcat">
  <doc id="697321" />
  <doc id="180008" />
 </query>

<interface>
   <url value="http://www.itdaan.com/getelevate.html"/>
</interface>


</elevate>

其中,interface就是我们可以配置的接口,直接可以返回需要竞价排名的数据。其中,接口返回的JSON数据如下:

[{"q":"nginx","ids":["697321","11298","150076","285875"],"eids":[]}]

q:表示关键词。ids:表示需要排名提前的docId。eids:需要过滤的docId。

关键字:   solr     竞价排名  
评论信息
暂无评论
发表评论
验证码: 
Powered by IMZHANGJIE.CN Copyright © 2015-2025 粤ICP备14056181号