背景
开发es查询程序,每次都要进行编码,大部分代码都是重复代码,实际上最后生成的就是json,简单🤔下,有没有开发人员都会的一种表达语言,将表达语言转换成json,
很明显sql可以,开发人员都会,然后生成项目时,只需用sql来描述,你想要的查询,然后把日期等参数在json中完成替换即可,即可生成查询结果。
es json 如下
{
"query":{
"term":{
"city":{
"value":"chengdou",
"boost":1
}
}
},
"_source":{
"includes":[
"name"
],
"excludes":[
]
}
}
antlr4
ANTLR 能够根据用户定义的语法文件自动生成词法分析器和语法分析器,并将输入文本处理为语法分析树。ANTLR 自动生成的编译器高效,能够将开发者从繁杂的编译理论中解放出来,集中精力处理自己的业务逻辑。
ANTRL 4 引入的自动语法分析树创建与遍历机制,极大地提高了语言识别程序的开发效率。我们广为熟知的大数据计算框架的 SQL 解析就是基于 ANTLR,比如 Hive(ANTLR 3)、Spark 2.x(ANTLR 4)、presto(ANTLR 4)等。
定义语法文件
grammar Es; // 定义一个名为ES的语法,名字与文件名一致
//语法结构
sql: selectoperation; //定义sql是一个查询操作
selectoperation:
'select' field 'from' table where ? ; //定义查询语句
field: ANYTHING # ANYTHING //子规则 *
| ID # id //子规则 匹配字母
;
table:ID;
where: 'where' expression ;
expression: ID '=' ID ;
//词法结构
ID : [a-zA-Z]+ ; // 匹配字母
ANYTHING : '*' ; // 查询 任务字符
查看生成的语法树
测试SQL select name from a where city='chengdou'
生成代码
idea中可以用插件来生成, 只需定义好语法文件即可
最后生成的结构如下
测试
// Generated from ANTLR 4.9.2
package com.example.spring.estest;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import java.util.Arrays;
import java.util.List;
/**
* This class provides an empty implementation of {@link EsVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class EsBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements EsVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitSql(EsParser.SqlContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitSelectoperation(EsParser.SelectoperationContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitANYTHING(EsParser.ANYTHINGContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitId(EsParser.IdContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitTable(EsParser.TableContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitWhere(EsParser.WhereContext ctx) {
return visitChildren(ctx);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public T visitExpression(EsParser.ExpressionContext ctx) {
return visitChildren(ctx);
}
public static void main(String[] args) {
// 对每一个输入的字符串,构造一个 ANTLRStringStream 流 in
ANTLRInputStream input = new ANTLRInputStream("select name from a where city='chengdou'");
// 用 in 构造词法分析器 lexer,词法分析的作用是将字符聚集成单词或者符号
EsLexer lexer = new EsLexer(input);
// 用词法分析器 lexer 构造一个记号流 tokens
CommonTokenStream tokens = new CommonTokenStream(lexer);
// 再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作
EsParser parser = new EsParser(tokens);
EsParser.SqlContext sql = parser.sql();
//找到查询子规则
EsParser.SelectoperationContext selectOperation = sql.selectoperation();
//找到查询列
String[] queryField = (String[]) Arrays.asList(selectOperation.field().getText()).toArray();
//查看where 表达式
List<TerminalNode> id = selectOperation.where().expression().ID();
//查看where 表达式里的内容
System.out.println(id.get(0).getText());
System.out.println(id.get(1).getText());
//生成es的查询语句
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.fetchSource(queryField, new String[0]);
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(id.get(0).getText(), id.get(1).getText());
searchSourceBuilder.query(termQueryBuilder);
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(searchSourceBuilder);
System.out.println(searchRequest.source());
}
}
结果
{
"query":{
"term":{
"city":{
"value":"chengdou",
"boost":1
}
}
},
"_source":{
"includes":[
"name"
],
"excludes":[
]
}
}
|