如何通过FunctionContributor实现MATCH() AGAINST()函数?
实现MySQL风格的MATCH AGAINST自定义SQL函数
我已经能实现ST_Y(?)或ST_DISTANCE_SPHERE(?,?)这类简单SQL函数,示例代码如下:
class StYFunction extends StandardSQLFunction { private static final BasicTypeReference<Double> RETURN_TYPE = new BasicTypeReference<Double>("double", double.class, SqlTypes.DOUBLE); public StYFunction(String name) { super(name, true, RETURN_TYPE); } @Override public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, ReturnableType<?> returnType, SqlAstTranslator<?> translator) { if (sqlAstArguments.size() != 1) { throw new IllegalArgumentException("Function " + getName() + " requires exactly 1 argument"); } sqlAppender.append("ST_Y("); sqlAstArguments.get(0).accept(translator); sqlAppender.append(")"); } }
但我需要实现MySQL中的MATCH(?) AGAINST(?)函数,它有两种使用场景:
- 简单场景:
MATCH(?,?) - 带匹配模式的场景:
MATCH (title,body) AGAINST ('database' IN NATURAL LANGUAGE MODE);
或者
MATCH (title,body) AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
实现思路
MATCH AGAINST的结构和普通函数不同,它是MATCH(列列表) AGAINST(搜索字符串 [匹配模式])的形式,需要支持2个或3个参数:
- 第一个参数是列名列表(支持单个或多个列)
- 第二个参数是搜索字符串
- 可选第三个参数是匹配模式(如
IN NATURAL LANGUAGE MODE)
完整实现代码
class MatchAgainstFunction extends StandardSQLFunction { // MATCH AGAINST返回相关性得分,使用Double类型 private static final BasicTypeReference<Double> RETURN_TYPE = new BasicTypeReference<Double>("double", double.class, SqlTypes.DOUBLE); public MatchAgainstFunction(String name) { super(name, true, RETURN_TYPE); } @Override public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, ReturnableType<?> returnType, SqlAstTranslator<?> translator) { int argCount = sqlAstArguments.size(); if (argCount < 2 || argCount > 3) { throw new IllegalArgumentException("Function " + getName() + " requires 2 or 3 arguments"); } // 拼接MATCH(列列表)部分 sqlAppender.append("MATCH("); sqlAstArguments.get(0).accept(translator); sqlAppender.append(") AGAINST("); // 拼接搜索字符串 sqlAstArguments.get(1).accept(translator); // 若有第三个参数,拼接匹配模式 if (argCount == 3) { sqlAppender.append(" "); sqlAstArguments.get(2).accept(translator); } sqlAppender.append(")"); } }
使用示例
- 简单场景调用:
MATCH_AGAINST([title, body], 'database'),最终生成SQL:MATCH(title,body) AGAINST('database') - 带布尔模式的调用:
MATCH_AGAINST([title, body], '+MySQL -YourSQL', 'IN BOOLEAN MODE'),最终生成SQL:MATCH(title,body) AGAINST('+MySQL -YourSQL' IN BOOLEAN MODE)
注意事项
- 确保第一个参数能被正确解析为多列表达式(比如传入逗号分隔的列集合)
- 匹配模式的字符串需和MySQL原生语法一致,关键字不区分大小写
- 参数数量校验覆盖了2个或3个参数的合法情况,非法参数数会抛出异常
内容的提问来源于stack exchange,提问作者hurelhuyag
相关产品推荐
相关产品推荐

