solr4.7.2自定義評分排序

概述

Solr提供ValueSourceParser來實現自定義評分函數,在自定義評分函數中封裝評分邏輯,然後根據自定義評分函數計算的值進行排序。

準備數據

將數據導入solr

原始查詢

q=sdes:共和國

fq=spopulation:[ 500000000 TO * ]

fl=*,score

排序默認使用score得分排序,可發現巴西的評分(0.15021087)比中國評分(0.1201687)高,那麼可以利用自定義評分函數的值,來實現重新排序

自定義評分邏輯

//默認得分都是1.0分
float boot = 1.0f;

//如果sarea不存在或者爲小,則減去0.2分
if (StringUtils.isBlank(sarea) || "小".equals(sarea)) {
   boot -= 0.2f;
}

//如果sname存在中,則增加0.2分
if (sname.contains("中")) {
   boot += 0.2f;
}

//如果spopulation大於500000000,則增加0.5分
if (spopulation > 500000000) {
   boot += 0.5f;
}

根據新的評分邏輯計算,巴西的評分(1.0),中國的評分(1.7)

編寫代碼

public class MyValueSourceParser extends ValueSourceParser {

    private final Logger log = LoggerFactory.getLogger(MyValueSourceParser.class);

    public MyValueSourceParser() {
        super();
    }

    @Override
    public ValueSource parse(FunctionQParser fp) throws SyntaxError {
        /**
         * 按順序取2個參數
         */
        String arg1 = fp.parseArg(); //取到第一個參數
        String arg2 = fp.parseArg(); //取到第二個參數
        log.info("MyFilterQParserPlugin arg1=" + arg1);
        log.info("MyFilterQParserPlugin arg2=" + arg2);

        /**
         * 獲取LocalParams
         */
        SolrParams solrParams = fp.getLocalParams();
        if (null != solrParams) {
            Iterator<String> it = solrParams.getParameterNamesIterator();
            while (it.hasNext()) {
                final String name = it.next();
                final String[] values = solrParams.getParams(name);
                for (String v : values) {
                    log.info("LocalParams name:" + v);
                }
            }
        }

        /**
         * 獲取Params
         */
        solrParams = fp.getParams();
        if (null != solrParams) {
            Iterator<String> it = solrParams.getParameterNamesIterator();
            while (it.hasNext()) {
                final String name = it.next();
                final String[] values = solrParams.getParams(name);
                for (String v : values) {
                    log.info("Params " + name + ":" + v);
                }
            }
        }

        /**
         *
         * 獲取三個字段的信息
         */
        ValueSource sareavs = getValueSource(fp, "id");
        ValueSource spopulationvs = getValueSource(fp, "spopulation");
        ValueSource snamevs = getValueSource(fp, "sname");

        /**
         * 將相關文檔的值傳給自定義的ValueSource方法,打分規則在自定義的ValueSource中定製
         */
        MyValueSource myValueSource = new MyValueSource(sareavs, spopulationvs, snamevs);

        return myValueSource;
    }

    /**
     * 該方法是根據字段名,從FunctionQParser得到文檔該字段的相關信息
     * @param fp
     * @param arg
     * @return
     */
    public ValueSource getValueSource(FunctionQParser fp, String arg) {
        if (arg == null) {
            return null;
        }
        SchemaField f = fp.getReq().getSchema().getField(arg);
        return f.getType().getValueSource(f, fp);
    }
}
public class MyValueSource extends ValueSource {
    private final Logger log = LoggerFactory.getLogger(MyValueSource.class);
    private ValueSource sareavs;
    private ValueSource spopulationvs;
    private ValueSource snamevs;

    public MyValueSource(ValueSource sareavs, ValueSource spopulationvs, ValueSource snamevs) {
        this.sareavs = sareavs;
        this.spopulationvs = spopulationvs;
        this.snamevs = snamevs;
    }

    @Override
    public FunctionValues getValues(Map context,AtomicReaderContext readerContext) throws IOException {

        final FunctionValues sareafv = sareavs.getValues(context,readerContext);
        final FunctionValues spopulationfv = spopulationvs.getValues(context,readerContext);
        final FunctionValues snamefv = snamevs.getValues(context,readerContext);

        return new FloatDocValues(this) {

            /**
             * 重寫floatVal方法,自定義打分排序規則
             * @param doc
             * @return
             */
            @Override
            public float floatVal(int doc) {
                String sarea = sareafv.strVal(doc);
                long spopulation = spopulationfv.longVal(doc);
                String sname = snamefv.strVal(doc);

                log.info(toString());

                float boot = 1.0f;

                if (StringUtils.isBlank(sarea) || "小".equals(sarea)) {
                    boot -= 0.2f;
                }

                if (sname.contains("中")) {
                    boot += 0.2f;
                }

                if (spopulation > 500000000) {
                    boot += 0.5f;
                }

                return boot;
            }

            @Override
            public String toString(int doc) {
                return name() + '(' + sareafv.strVal(doc) + ',' + spopulationfv.strVal(doc) + ',' + snamefv.strVal(doc) + ')';
            }
        };
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (obj == null) {
            return false;
        } else if (this.getClass() != obj.getClass()) {
            return false;
        } else {
            MyValueSource other = (MyValueSource) obj;
            if (this.sareavs == null) {
                if (other.sareavs != null) {
                    return false;
                }
            } else if (!this.sareavs.equals(other.sareavs)) {
                return false;
            }

            if (this.spopulationvs == null) {
                if (other.spopulationvs != null) {
                    return false;
                }
            } else if (!this.spopulationvs.equals(other.spopulationvs)) {
                return false;
            }

            if (this.snamevs == null) {
                if (other.snamevs != null) {
                    return false;
                }
            } else if (!this.snamevs.equals(other.snamevs)) {
                return false;
            }

            return true;
        }
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + (this.sareavs == null ? 0 : this.sareavs.hashCode());
        result = 31 * result + (this.spopulationvs == null ? 0 : this.spopulationvs.hashCode());
        result = 31 * result + (this.snamevs == null ? 0 : this.snamevs.hashCode());
        return result;
    }

    @Override
    public String description() {
        return name();
    }

    public String name() {
        return "MyValueSource";
    }

}

solrconfig配置

配置插件名稱和關聯類

<valueSourceParser name="myValueSource"  class="cn.sing.plugin.valuesource.MyValueSourceParser" />

使用方式:

  • sort={!func}myValueSource("1","2") asc
  • fl=*,score,_val_:myValueSource("1","2") 

lib路徑

將上面編寫的2個類打包放到lib引用的目錄中,lib也編寫在solrconfig配置中

<lib dir="D:\Soft\solr-cloud\solorconfig\testindex\javalib" regex=".*\.jar" />

重新查詢

q=sdes:共和國

fq=spopulation:[ 500000000 TO * ]

fl=*,score,_val_:myValueSource("1","2")

sort={!func}myValueSource("1","2") desc

執行日誌

INFO  - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg1=1
INFO  - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg2=2
INFO  - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; LocalParams v:myValueSource("1","2") desc
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; LocalParams type:func
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params distrib:false
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params fl:id,score
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params start:0
INFO  - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params fsv:true
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params fq:spopulation:[ 500000000 TO * ]
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params sort:{!func}myValueSource("1","2") desc
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params shard.url:http://127.0.0.1:8891/solr/testindex_shard2_replica1/
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params version:2
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params q:sdes:���͹�
INFO  - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO  - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params NOW:1582012921733
INFO  - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params isShard:true
INFO  - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params wt:javabin
INFO  - 2020-02-18 16:02:01.759; org.apache.solr.core.SolrCore; [testindex_shard2_replica1] webapp=/solr path=/select params={distrib=false&fl=id,score&start=0&fsv=true&fq=spopulation:[+500000000+TO+*+]&sort={!func}myValueSource("1","2")+desc&shard.url=http://127.0.0.1:8891/solr/testindex_shard2_replica1/&rows=10&version=2&q=sdes:���͹�&defType=lucene&NOW=1582012921733&isShard=true&wt=javabin} hits=0 status=0 QTime=6 
INFO  - 2020-02-18 16:02:01.790; org.apache.solr.core.SolrCore; [testindex_shard2_replica1] webapp=/solr path=/select params={q=sdes:���͹�&indent=true&fl=*,score,_val_:myValueSource("1","2")&fq=spopulation:[+500000000+TO+*+]&sort={!func}myValueSource("1","2")+desc&wt=json} hits=2 status=0 QTime=57 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章