zoukankan      html  css  js  c++  java
  • Solr高亮与Field权重

    Solr高亮与Field权重

     

    Solr高亮

    原理

    做搜索时,高亮是很常见的需求,那么Solr肯定也为高亮提供了支持。先解释下Solr高亮的原理,在我们设置了需要高亮显示的Field之后,查询得到的返回结果会多出来下面的内容:

    复制代码
    "highlighting": {
    
    "519": {
    
    "Artist_Name": [
    
    "<em>周杰伦</em>"
    
    ]
    }
    }
    复制代码

    其实就是多了highlighting的字段,并没有改变原来返回的字段内容。

    Json串是使用 Unique Field :{高亮显示的内容}的形式。

    SolrJ有三种高亮类型:

    如果要对某field做高亮显示,必须对该field设置stored=true

    Standard Highlighter,根据查询的docIdSet,获取Documents,并获取当前document的需要高亮的field的value,根据query的term和该field的value做匹配算法
    FastVector Highlighter,效率比普通的高亮显示要高;需要定义termvector(占用空间和IO),包括position和offset,根据query term的termvector到field value中做快速的定位标记,进而实现快速的高亮显示
    Postings Highlighter,由于高亮显示需要对field设置为store=true,所有对于单节点数据量比较大并且该字段比较大的话,会消耗大量的IO操作,那么可以把该字段存储在另外的地方,比如Hbase,在外部做高亮显示的匹配。

    其中推荐使用的是Standard Highlighter,下面也是针对Standard Highlighter,

    配置

    下面介绍两种配置方式:

      1.SolrJ配置:

    复制代码
    //设置高亮
    songQuery.setHighlight(true); // 开启高亮组件或用query.setParam("hl", "true");     songQuery.addHighlightField("Song_Name,Song_SingerName");// 高亮字段
    songQuery.set("hl.highlightMultiTerm","true");//启用多字段高亮
    songQuery.setHighlightSimplePre("<font style="color:#A7D043;font-weight:bold;">"); //标记,高亮关键字前缀
    songQuery.setHighlightSimplePost("</font>");//后缀
    复制代码

      2.solrConfig.xml配置: 

    复制代码
    <requestHandler name="search" class="solr.SearchHandler" default="true">
    <!-- default values for query parameters can be specified, these
            will be overridden by parameters in the request
    -->
      <lst name="defaults">
        <str name="echoParams">explicit</str>
          <int name="rows">10</int>
          <str name="df">text</str>
       <str name="hl">true</str>
       <str name="hl.fl">content</str>
       <str name="f.name.hl.fragsize">50</str>
       <str name="hl.simple.pre">&lt;font color=&quot;red&gt;</str>
       <str name="hl.simple.post">&lt;/font&gt;</str>
      </lst>
    </requestHandler>
    复制代码

    详细的RequestHandler配置请参看博客:五、SolrJ、Request Handler

    其实这两种配置并没有本质上的区别。我个人习惯使用SolrJ配置。

    解析

    获取highlighting是非常简单的,一条语句搞定:

    Map<String,Map<String,List<String>>> tempMap = response.getHighlighting();

    相信大家也注意到了,虽然接受结果简单,但是如果想遍历就比较复杂了,因为接受到的结果是嵌套了很多层的类型Map<String,Map<String,List<String>>>

    那么我这边把我解析的方法分享下:

    复制代码
    Map<String,Map<String,List<String>>> tempMap = songHighlight.getHighlighting();
             for(Map.Entry<String, Map<String,List<String>>> entry : tempMap.entrySet()) {
                if(Integer.parseInt(entry.getKey()) == song.getSong_SongID()) {
     
                   for(Map.Entry<String, List<String>> entryLayer2 : entry.getValue().entrySet()) {
                      if(null != entryLayer2.getKey() && "Song_Name".equals(entryLayer2.getKey())) {
                         //your Operation
                      }
                      if(null != entryLayer2.getKey() && "Song_SingerName".equals(entryLayer2.getKey())) {
                         //your Operation
                      }
                   }
                }
             }
    复制代码

    这个方法比Iterator和foreach效率稍高。

    我设置了两个字段需要高亮,所以在循环中判断了高亮是属于哪个字段,之后进行相应的操作。

    因为我做的时候,一首歌可能有几个Song_SingerName,在数据库中用"/"分隔,所以这种情况更加复杂,我首先是把后缀中的/换成了出现概率很小的@

    songQuery.setHighlightSimplePost("<@font>");//后缀

    然后再用split("@")分隔出不同的Song_SingerName,但是这样就会有一个问题,就是我不知道高亮的歌手到底是哪一个歌手,所以这个时候,我还需要从分割后的String[]中提取所有的中文字符,比对后,存入另一个变量,最后再用"/"替换掉"@"。

     

    Solr权重

    概念

    Solr底层依然用的是Lucene的权重算法,也就是通过一个公式计算每个Documents的得分,然后按得分高低排序,公式如下:

    简单解释下这个公式中包含的一些因子:

    Tf:Term frequency,就是条目出现的次数。

    Idf: Inverse document frequency,就是用来描述在一个搜索关键字中,不同字词的稀有程度。比如搜索The Cat in the Hat,那么很明显The和in远没有Cat和Hat重要。

    Boosting:这个使我们设置权重的重点,比如搜索歌手名,那么在一个document中还有歌手的ID、歌曲的清晰度、歌曲上传时间,而boosting是不同的Filed有不同权重,之后根据公式计算得分。所以可以看到,我们并不能直接影响solr搜索结果的排序,需要改变权重,进而改变不同Document的得分,从而影响排序。

    其中还有很多因子和公式的解释,有兴趣的同学可以参考Solr in action这本书,里面有比较详细的解释。

    因为我们只需简单的根据某一Filed的权重影响结果的排序,所以我们需要改变Document的Boosting,那么就需要用到Dismax,Dismax是一个查询解析器(Query parser),查询解析器的概念就是提供了一系列查询的参数,一旦我们在查询url中设置了相应的参数,那么查询解析器将会解析查询信息,从而得到搜索结果,其实完全也可以把查询解析器理解为一个Api,就是提供了相应的方法,我们设置,之后Solr根据我们设置的参数进行查询,只不过不同的Query Parser提供了不同的参数而已。

    一共提供了三种Query Parser

    Standard:最常用的,并且是默认

    Dismax:

    Extended Dismax

    功能从上至下是逐渐递增的,在大部分情况下,Standard已经可以完全满足需求,但是因为要使用权重排序,那么需要用到Dismax,具体提供的参数请查看wiki:

    https://cwiki.apache.org/confluence/display/solr/The+Standard+Query+Parser

    那么首先需要设置Query Parser为Dismax:

    songQuery.set("defType","dismax");

    之后设置需要查询的Field:

    songQuery.set("qf","Song_Name^2 Song_SingerName^0.2");

    比如我这里就需要根据用户输入的关键字查询歌手名和歌曲名,之后返回这两个Field命中的结果、多个Query Filed中可以设置不同的权重,比如Song_Name的权重就为2,必须注意,在Solr权重的设置中,所有权重标准为1,意思是当权重设置大于1时,代表这个字段的权重变大,如果权重设置小于1并且大于0的时候,代表这个字段权重变小。

    之后设置其它Field的权重:

    songQuery.set("bf", "sum(div(Song_Quality,0.01),if(exists(Song_FileMV),20000,0),recip(ms(NOW,Song_CreateTimeForNew),1,10000,1))");

    这里面用到了很多Function Query,比如div,代表相除、exists代表如果Song_FileMV如果不为空那么设置它的权重为20000,为空则为0。记住最后要sum起来,因为从上面的公式可以看出来,boosting是一个变量,所以最好要有一个和值。相关的函数请参考wiki:

    http://wiki.apache.org/solr/FunctionQuery

    这样搜索结果就会按照有MV的优先显示、最近上传的优先显示、清晰度高的优先显示。

    作者<ahref="http: www.cnblogs.com="" edwinchen="" "="" target"_blank"="">瞪着太阳的乌鸦

     
    分类: Solr
  • 相关阅读:
    Window 窗口类
    使用 Bolt 实现 GridView 表格控件
    lua的table库
    Windows编程总结之 DLL
    lua 打印 table 拷贝table
    使用 xlue 实现简单 listbox 控件
    使用 xlue 实现 tips
    extern “C”
    COleVariant如何转换为int double string cstring
    原来WIN32 API也有GetOpenFileName函数
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3979017.html
Copyright © 2011-2022 走看看