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.sing.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg1=1
INFO  - 2020-02-18 16:02:01.755; cn.sing.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg2=2
INFO  - 2020-02-18 16:02:01.755; cn.sing.plugin.valuesource.MyValueSourceParser; LocalParams v:myValueSource("1","2") desc
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; LocalParams type:func
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params distrib:false
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params fl:id,score
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params start:0
INFO  - 2020-02-18 16:02:01.756; cn.sing.plugin.valuesource.MyValueSourceParser; Params fsv:true
INFO  - 2020-02-18 16:02:01.757; cn.sing.plugin.valuesource.MyValueSourceParser; Params fq:spopulation:[ 500000000 TO * ]
INFO  - 2020-02-18 16:02:01.757; cn.sing.plugin.valuesource.MyValueSourceParser; Params sort:{!func}myValueSource("1","2") desc
INFO  - 2020-02-18 16:02:01.757; cn.sing.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.sing.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO  - 2020-02-18 16:02:01.757; cn.sing.plugin.valuesource.MyValueSourceParser; Params version:2
INFO  - 2020-02-18 16:02:01.757; cn.sing.plugin.valuesource.MyValueSourceParser; Params q:sdes:���͹�
INFO  - 2020-02-18 16:02:01.757; cn.sing.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO  - 2020-02-18 16:02:01.758; cn.sing.plugin.valuesource.MyValueSourceParser; Params NOW:1582012921733
INFO  - 2020-02-18 16:02:01.758; cn.sing.plugin.valuesource.MyValueSourceParser; Params isShard:true
INFO  - 2020-02-18 16:02:01.758; cn.sing.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 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Solr是一个基于Java的搜索引擎,可以用Java实现自定义排序。以下是实现自定义排序的步骤: 1. 创建一个自定义排序器类,实现org.apache.solr.search.SortComparator。 2. 在自定义排序器类中实现compare方法,该方法接收两个参数,即要比较的文档对象。 3. 在compare方法中实现自定义排序逻辑,根据需要将文档对象进行排序。 4. 在solrconfig.xml文件中配置自定义排序器,将其添加到fieldType中。 5. 在查询请求中指定使用自定义排序器。 下面是一个示例代码,演示了如何使用Java实现自定义排序器: ```java public class CustomSortComparator extends SortComparator { @Override public int compare(SortField sortField, SchemaField schemaField, FieldComparator<?> fieldComparator1, FieldComparator<?> fieldComparator2) throws IOException { // 获取要比较的文档对象 Object value1 = fieldComparator1.value(sortField.getReverse()); Object value2 = fieldComparator2.value(sortField.getReverse()); // 根据自定义逻辑进行排序 if (value1 instanceof Long && value2 instanceof Long) { Long long1 = (Long) value1; Long long2 = (Long) value2; if (long1 > long2) { return sortField.getReverse() ? -1 : 1; } else if (long1 < long2) { return sortField.getReverse() ? 1 : -1; } else { return 0; } } // 默认情况下,按照Solr默认的排序逻辑进行排序 return super.compare(sortField, schemaField, fieldComparator1, fieldComparator2); } } ``` 在solrconfig.xml文件中配置自定义排序器: ```xml <fieldType name="text_custom" class="solr.TextField"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> </analyzer> <sortComparator class="com.example.CustomSortComparator"/> </fieldType> ``` 在查询请求中指定使用自定义排序器: ```sh http://localhost:8983/solr/mycore/select?q=*:*&sort=custom_field+desc&fl=field1,field2&defType=edismax&wt=json ``` 以上代码演示了如何使用Java实现自定义排序器,通过实现compare方法自定义排序逻辑,将自定义排序器添加到fieldType中,在查询请求中指定使用自定义排序器。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值