记录一次solr自定义函数编写及使用的过程

简介: solr基本查询已经可以满足大多数查询场景,不过作为一款成熟的搜索引擎solr也可以支持编写自定义函数udf并在查询中使用以应对各种复杂的查询场景。

背景:目前我们solr中存储的数据因为很多属性字段的不确定性,选择将数据在一个大字段中合并。如下格式中attr字段代表着一个不确定的属性字段,可能为身高、体重、性别等,也可能为页码、出版方、售价等

{

“id”:“1”

“attr”:“180,80,男”

“type”:“person”

},

{

“id”:“2”

“attr”:“50,人民出版社,50¥”

“type”:“book”

}

针对这种近期产品提出一个要针对人类按照身高排序,书籍类按照售价排序。这种需求怎么搞呢?身高属性已经跟其他属性混为一个字段,常规排序怕是行不通。

思路:既然常规思路行不通,我们想能不能通过函数截取的方式通过比对该字符串指定位置来实现排序呢?下面直接上代码

代码:首先需要定义两个类SubStrValueSourceParser

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.FunctionQParser;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.ValueSourceParser;
public class SubStrValueSourceParser extends ValueSourceParser {
    public SubStrValueSourceParser() {
        super();
    }
    @Override
    public ValueSource parse(FunctionQParser fp) throws SyntaxError {
        String fieldStr = fp.parseArg();//第一个参数
        String bgnLocation = fp.parseArg();//第二个参数数组下标
        ValueSource location = getValueSource(fp, fieldStr);//取得函数调用时指定字段值
//将参数及需要的文档的值传给自定义的ValueSource方法,打分规则在自定义的ValueSource中定制
        SubStrValueSource stringFieldSource = new SubStrValueSource(location, bgnLocation);
        return stringFieldSource;
    }
//该方法是根据字段名,从FunctionQParser得到文档该字段的相关信息
    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);
    }
}
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import org.apache.lucene.queries.function.docvalues.FloatDocValues;
import org.apache.lucene.queries.function.docvalues.IntDocValues;
import org.apache.lucene.queries.function.docvalues.StrDocValues;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class SubStrValueSource extends ValueSource {
    private ValueSource attr13;//需要进行格式转换的字段
    private String location;
    //通过构造方法获取字段
    public SubStrValueSource(ValueSource attr13, String location) {
        this.attr13 = attr13;
        this.location = location;
    }
    @Override
    public FunctionValues getValues(Map map, LeafReaderContext leafReaderContext) throws IOException {
        final FunctionValues fieldValues = attr13.getValues(map,
                leafReaderContext);//获取attr13的值
        return new DoubleDocValues(this) {
            @Override
            public double doubleVal(int i) throws IOException {
                String fieldStr = null;
                Double retValue = 0.00;
                //若要被转化的值为空或者为空字符串则返回0
                if (fieldValues.strVal(i) == null || "".equals(fieldValues.strVal(i))) {
                } else {
                    fieldStr = fieldValues.strVal(i);
                    String[] vList = fieldStr.split(",");
                    //若实际数组长度小于下标则不处理直接返回0,若大于或等于下标则截取对应位置数据
                    if (vList.length < Integer.parseInt(location) + 1) {
                    } else {
                        String content = vList[Integer.parseInt(location)];
                        retValue = Double.parseDouble(content);
                    }
                }
                return retValue;
            }
        };
    }
    @Override
    public boolean equals(Object o) {
        return true;
    }
    @Override
    public int hashCode() {
        return 0;
    }
    @Override
    public String description() {
        return name();
    }
    public String name() {
        return "subStr";
    }
}

发布:代码逻辑编写完毕后打成jar包并按照如下步骤操作

  1. 在solr安装目录下dist目录中将打好的jar包放进去
  2. 在solrconfig.xml中新增以下配置

<lib dir="${solr.install.dir:../../../..}/dist/" regex="com.tl.solr.*\.jar" />

<valueSourceParser name="subStr"

                       class="SubStrValueSourceParser" />

搞定之后重启服务生效

使用效果:

1646278833(1).png

1646278927(1).png


相关文章
|
存储 SQL Oracle
Oracle存储过程中如何使用数组(附范例)
Oracle存储过程中如何使用数组(附范例)
|
1月前
|
Java
ETL工具 Kettle 中 kettle循环传递变量_(最简单的方法)
本文详细介绍了如何在Kettle工具中使用循环传递变量,通过示例展示了如何将movies表数据按月插入到ods_movies表,涉及新建转换、获取变量、作业配置和执行,呈现了一个嵌套作业结构.
82 3
|
4月前
|
分布式计算 大数据 数据处理
MaxCompute操作报错合集之编写UDF(用户自定义函数)时,报错:找不到主类,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
119 1
|
6月前
|
SQL 搜索推荐 Java
Hive中的UDF是什么?请解释其作用和使用方法。
Hive中的UDF是什么?请解释其作用和使用方法。
91 0
|
6月前
|
SQL 数据采集 Java
Java【代码分享 02】商品全部分类数据获取(建表语句+Jar包依赖+树结构封装+获取及解析源代码)包含csv和sql格式数据下载可用
Java【代码分享 02】商品全部分类数据获取(建表语句+Jar包依赖+树结构封装+获取及解析源代码)包含csv和sql格式数据下载可用
77 0
|
6月前
|
SQL 关系型数据库 数据库
PostgreSQL【应用 02】扩展SQL之C语言函数(编写、编译、载入)实例分享
PostgreSQL【应用 02】扩展SQL之C语言函数(编写、编译、载入)实例分享
202 0
|
6月前
|
Oracle Java 关系型数据库
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
117 0
|
SQL 关系型数据库 MySQL
Loadrunner脚本优化-参数化之关联MySQL数据库获取数据
Loadrunner脚本优化-参数化之关联MySQL数据库获取数据
112 0
|
SQL JSON 分布式计算
spark2 sql读取数据源编程学习样例2:函数实现详解
spark2 sql读取数据源编程学习样例2:函数实现详解
90 0
spark2 sql读取数据源编程学习样例2:函数实现详解
|
存储 SQL Oracle
Oracle存储过程与存储函数-入门
Oracle存储过程与存储函数-入门