普通查询串如k=v&k=v&(k=v||k=v)&k=v1|v2
转换为es的查询java查询实体
思路:
1.解析字符串,获取单词
2.根据单词构建ast抽象语法树
3.解析该抽象语法树,转换为es-java-api
public class AstNode {
private String key;
private AstNode left;
private Operator operator;
private AstNode right;
private String value;
//普通token时存储text
private String text;
public AstNode() {
}
public AstNode(String text) {
this.text = text;
}
public boolean isReference(){
if ((key == null || "".equals(key)) && left != null){
return true;
}
return false;
}
public String getKey() {
return key;
}
public void setKey(String key) {
if (key == null || "".equals(key)){
throw new RuntimeException("filter is error");
}
this.key = key;
}
public AstNode getLeft() {
return left;
}
public void setLeft(AstNode left) {
this.left = left;
}
public Operator getOperator() {
return operator;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
public AstNode getRight() {
return right;
}
public void setRight(AstNode right) {
this.right = right;
}
public String getValue() {
return value;
}
public void setValue(String value) {
if (value == null || "".equals(value)){
throw new RuntimeException("filter is error");
}
this.value = value;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
public enum Operator {
AND("&", false, 10),
OR("||", false,10),
EQUAL("=", true, 20),
NOT_EQUAL("!=", true, 20),
GT(">", true, 20),
GTE(">=", true, 20),
LT("<", true, 20),
LTE("<=", true, 20)
;
private String text;
private boolean basicOp;
private int priority;
Operator(String text, boolean basicOp, int priority) {
this.text = text;
this.basicOp = basicOp;
this.priority = priority;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public boolean isBasicOp() {
return basicOp;
}
public void setBasicOp(boolean basicOp) {
this.basicOp = basicOp;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public static Operator get(String text){
for (Operator o : Operator.values()){
if (o.text.equals(text)){
return o;
}
}
return null;
}
}
public class Token {
public enum TokenType {
STRING,
NUMBER,
OPERATOR,
PARENTHESIS;
}
private String text;
private TokenType tokenType;
public Token() {
}
public Token(String text, TokenType tokenType) {
this.text = text;
this.tokenType = tokenType;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public TokenType getTokenType() {
return tokenType;
}
public void setTokenType(TokenType tokenType) {
this.tokenType = tokenType;
}
}
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
public class TokenReader extends StringReader {
/**
* Creates a new string reader.
*
* @param s String providing the character stream.
*/
public TokenReader(String s) {
super(s);
}
public List<Token> getTokens() throws IOException {
List<Token> tokens = new LinkedList<>();
int ci = -1;
while ((ci = read()) != -1){
this.reset();
if (isKey()){
Token key = getKey();
tokens.add(key);
} else if(isComparer()){
Token comparer = getComparer();
tokens.add(comparer);
Token value = getValue();
checkValue(value.getText());
tokens.add(value);
} else if (isOperatorAndOr()){
Token spliter = getOperatorAndOr();
tokens.add(spliter);
} else if (isParenthesis()){
char c = (char) read();
mark(0);
Token token = new Token();
token.setText(c+"");
token.setTokenType(Token.TokenType.PARENTHESIS);
tokens.add(token);
} else {
throw new RuntimeException("filter is error");
}
}
return tokens;
}
public boolean isKey() throws IOException {
int read = this.read();
this.reset();
if (read == -1){
throw new RuntimeException("filter is end");
} else {
char c = (char) read;
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'){
return true;
} else {
return false;
}
}
}
public Token getKey() throws IOException {
int ci = -1;
StringBuilder sb = new StringBuilder("");
while ((ci = read()) != -1){
char c = (char) ci;
if (isKeyCharator(c)){
sb.append(c);
this.mark(0);
} else {
reset();
Token token = new Token();
token.setTokenType(Token.TokenType.STRING);
token.setText(sb.toString());
return token;
}
}
return null;
}
public boolean isKeyCharator(char c) throws IOException {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || c == '.'){
return true;
} else {
return false;
}
}
public boolean isComparer() throws IOException {
int read = read();
this.reset();
if (read == -1){
throw new RuntimeException("filter is error");
} else {
char c = (char)read;
if (c == '=' || c == '!' || c == '>' || c == '<'){
return true;
} else {
return false;
}
}
}
public Token getComparer() throws IOException {
int read = read();
mark(0);
if (read == -1){
throw new RuntimeException("filter is error");
} else {
char c = (char) read;
if (c == '='){
Token token = new Token();
token.setText("=");
token.setTokenType(Token.TokenType.OPERATOR);
return token;
} else if (c == '!'){
c = (char) read();
if (c != '='){
throw new RuntimeException("filter is error");
} else {
Token token = new Token();
token.setText("!=");
token.setTokenType(Token.TokenType.OPERATOR);
mark(0);
return token;
}
} else if (c == '>'){
c = (char) read();
if (c != '='){
reset();
Token token = new Token();
token.setText(">");
token.setTokenType(Token.TokenType.OPERATOR);
return token;
} else {
Token token = new Token();
token.setText(">=");
token.setTokenType(Token.TokenType.OPERATOR);
mark(0);
return token;
}
} else if (c == '<'){
c = (char) read();
if (c != '='){
reset();
Token token = new Token();
token.setText("<");
token.setTokenType(Token.TokenType.OPERATOR);
return token;
} else {
Token token = new Token();
token.setText("<=");
token.setTokenType(Token.TokenType.OPERATOR);
mark(0);
return token;
}
}
}
return null;
}
public Token getValue() throws IOException {
int ci = read();
reset();
if (ci == -1){
throw new RuntimeException("filter is error");
}
Token token = new Token();
StringBuilder sb = new StringBuilder("");
while ((ci = read()) != -1){
char c = (char) ci;
if (c == '|' || c == '&' || c == '(' || c == ')'){
if (c == '|'){
char n = (char) read();
if (n == '|'){
reset();
token.setTokenType(Token.TokenType.STRING);
token.setText(sb.toString());
return token;
} else {
sb.append(c).append(n);
this.mark(0);
}
} else {
reset();
token.setTokenType(Token.TokenType.STRING);
token.setText(sb.toString());
return token;
}
} else {
sb.append(c);
this.mark(0);
}
}
token.setTokenType(Token.TokenType.STRING);
token.setText(sb.toString());
return token;
}
public boolean isOperatorAndOr() throws IOException {
int read = read();
this.reset();;
if (read == -1){
throw new RuntimeException("filter is error");
} else {
char c = (char) read;
if (c == '&' || c == '|'){
return true;
} else {
return false;
}
}
}
public Token getOperatorAndOr() throws IOException {
int read = read();
mark(0);
if (read == -1){
throw new RuntimeException("filter is error");
} else {
char c = (char) read;
if (c == '&'){
Token token = new Token();
token.setText("&");
token.setTokenType(Token.TokenType.OPERATOR);
return token;
} else if (c == '|'){
c = (char)read();
if (c != '|'){
throw new RuntimeException("filter is error");
} else {
mark(0);
Token token = new Token();
token.setText("||");
token.setTokenType(Token.TokenType.OPERATOR);
return token;
}
}
}
return null;
}
public boolean isParenthesis() throws IOException {
int read = read();
reset();
if (read == -1){
throw new RuntimeException("filter is error");
} else {
char c = (char) read;
if (c == '(' || c == ')'){
return true;
} else {
return false;
}
}
}
public void checkValue(String value){
//value为空
if (value == null || "".equals(value)){
throw new RuntimeException("filter is error");
}
//如果包含_,则剩余字符全部为数字
if (value.contains("_")){
//如果为排序字段,则为正常
if (value.toLowerCase().contains("desc") || value.toLowerCase().contains("asc")){
return;
}
if (!Transfer.isNumberOne_(value)){
throw new RuntimeException("filter is error");
}
}
//如果包含竖杠|,则必须为数字
if (value.contains("|")){
if (!Transfer.isNumberAndYaxis(value)){
throw new RuntimeException("filter is error");
}
}
//
}
public Token getStringValue(){
return null;
}
public Token getNumber(){
return null;
}
public static void main(String[] args) throws IOException {
List<Token> tokens = t.getTokens();
StringBuilder sb = new StringBuilder();
for (Token token : tokens){
sb.append(token.getText()).append(" ");
}
System.out.println(sb.toString());
}
}
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import java.io.IOException;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Transfer {
private class SortAndScroll{
public String sortField;
public String sort;
public int page;
public int size;
}
public SearchSourceBuilder transfer(String filter, int timeout) throws IOException {
//1.去掉空格
String f1 = filter.replaceAll(" ", "");
filter = f1;
if (filter.length() > 255){
throw new RuntimeException("filter is too long");
}
//括号是否匹配
parenthesisCheck(filter);
//page和size是否同时出现
pageSizeCheck(filter);
TokenReader tokenReader = new TokenReader(filter);
List<Token> tokens = tokenReader.getTokens();
AstNode astNode = transferAst(tokens);
SearchSourceBuilder searchSourceBuilder = transferES(astNode, timeout);
return searchSourceBuilder;
}
private void parenthesisCheck(String filter){
int length = filter.length();
int k = 0;
for (int i = 0;i < length; i++){
if (filter.charAt(i) == '('){
k++;
} else if (filter.charAt(i) == ')'){
k--;
}
}
if (k != 0){
throw new RuntimeException("filter is error");
}
}
private void pageSizeCheck(String filter){
if (filter.contains("page")){
if (!filter.contains("size")){
throw new RuntimeException("filter is error page size is missing");
}
}
if (filter.contains("size")){
if (!filter.contains("page")){
throw new RuntimeException("filter is error page size is missing");
}
}
}
private AstNode transferAst(List<Token> tokens){
Deque<AstNode> constantDeque = new LinkedList<>();
Deque<Token> operatorDeque = new LinkedList<>();
for (Token t : tokens){
if (t.getTokenType() == Token.TokenType.STRING){
constantDeque.push(new AstNode(t.getText()));
} else {
if (t.getText().equals("(")){
operatorDeque.push(t);
} else if (t.getTokenType() == Token.TokenType.OPERATOR){
/**
* 1.如果栈为空,则直接入栈
* 2.如果栈顶元素为(,则直接入栈
* 3.如果栈顶元素优先级<=t的优先级,不停弹出,直到栈顶元素为(或者是栈顶元素优先级>t的优先级
* 4.如果栈顶元素>t的优先级,直接入栈
*/
while (true){
if (operatorDeque.isEmpty()){
operatorDeque.push(t);
break;
} else if (operatorDeque.peek().getText().equals("(")){
operatorDeque.push(t);
break;
} else if (getPriority(t) <= getPriority(operatorDeque.peek())){
AstNode astNode = new AstNode();
Token top = operatorDeque.pop();
Operator operator = Operator.get(top.getText());
if (operator.isBasicOp()){
astNode.setOperator(operator);
astNode.setValue(constantDeque.pop().getText());
astNode.setKey(constantDeque.pop().getText());
} else {
astNode.setOperator(operator);
astNode.setRight(constantDeque.pop());
astNode.setLeft(constantDeque.pop());
}
constantDeque.push(astNode);
} else {
operatorDeque.push(t);
break;
}
}
} else if (t.getText().equals(")")){
//依次弹出栈中元素,直到(
while (!operatorDeque.peek().getText().equals("(")){
AstNode astNode = new AstNode();
Token top = operatorDeque.pop();
Operator operator = Operator.get(top.getText());
if (operator.isBasicOp()){
astNode.setOperator(operator);
astNode.setValue(constantDeque.pop().getText());
astNode.setKey(constantDeque.pop().getText());
} else {
astNode.setOperator(operator);
astNode.setRight(constantDeque.pop());
astNode.setLeft(constantDeque.pop());
}
constantDeque.push(astNode);
}
//弹出(
operatorDeque.pop();
} else {
throw new RuntimeException("filter is error");
}
}
}
//处理特殊情况操作符
while (!operatorDeque.isEmpty()){
Token pop = operatorDeque.pop();
if (pop.getText().equals("(")){
throw new RuntimeException("filter is error");
} else {
Operator o = Operator.get(pop.getText());
AstNode astNode = new AstNode();
if (o.isBasicOp()){
astNode.setOperator(o);
astNode.setValue(constantDeque.pop().getText());
astNode.setKey(constantDeque.pop().getText());
} else {
astNode.setOperator(o);
astNode.setRight(constantDeque.pop());
astNode.setLeft(constantDeque.pop());
}
constantDeque.push(astNode);
}
}
if (constantDeque.size() != 1){
throw new RuntimeException("filter is error");
}
return constantDeque.pop();
}
private SearchSourceBuilder transferES(AstNode astNode, int timeout){
SortAndScroll sortAndScroll = new SortAndScroll();
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilderInner = QueryBuilders.boolQuery();
preOrder(astNode, boolQueryBuilderInner, sortAndScroll);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.filter(boolQueryBuilderInner);
sourceBuilder.query(boolQueryBuilder);
if (sortAndScroll.sortField != null && !"".equals(sortAndScroll.sortField)){
if (sortAndScroll.sort == null || "".equals(sortAndScroll.sort) || sortAndScroll.sort.equals("desc")){
sourceBuilder.sort(sortAndScroll.sortField, SortOrder.DESC);
} else {
sourceBuilder.sort(sortAndScroll.sortField, SortOrder.ASC);
}
}
if (sortAndScroll.size > 0){
sourceBuilder.from((sortAndScroll.page-1)*sortAndScroll.size);
sourceBuilder.size(sortAndScroll.size);
}
sourceBuilder.timeout(new TimeValue(timeout, TimeUnit.SECONDS));
return sourceBuilder;
}
private void preOrder(AstNode astNode, BoolQueryBuilder boolQueryBuilder, SortAndScroll sortAndScroll){
if (!astNode.isReference()){
Operator operator = astNode.getOperator();
if (operator == Operator.EQUAL){
//剔除元素:分页,排序
if (astNode.getKey().equalsIgnoreCase("page")
|| astNode.getKey().equalsIgnoreCase("size")
|| astNode.getKey().equalsIgnoreCase("sort")){
if (astNode.getKey().equalsIgnoreCase("page")){
int i = Integer.parseInt(astNode.getValue());
if (i <= 0){
throw new RuntimeException("filter is error, page is error");
}
sortAndScroll.page = i;
} else if (astNode.getKey().equalsIgnoreCase("size")){
sortAndScroll.size = Integer.parseInt(astNode.getValue());
} else if (astNode.getKey().equalsIgnoreCase("sort")){
if (astNode.getValue().contains("_")){
sortAndScroll.sortField = astNode.getValue().split("_")[0];
sortAndScroll.sort = astNode.getValue().split("_")[1].toLowerCase();
} else {
sortAndScroll.sortField = astNode.getValue();
}
}
return;
}
/**
* 分为:
* 1.value全部为数字,则使用must term
* 3.value为数字和|,则使用should term
* 2.value除去数字外,包含一个下划线_,则使用rang
* 4.value为单独*,则使用存在
* 5.value为!*,则使用不存在
* 6.其他则使用match
*/
if (isNumber(astNode.getValue())){
boolQueryBuilder.must(QueryBuilders.termQuery(astNode.getKey(), astNode.getValue()));
} else if (isNumberOne_(astNode.getValue())){
firstLastIndexIs_(astNode.getValue());
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.from(astNode.getValue().split("_")[0])
.to(astNode.getValue().split("_")[1])
.includeLower(true);
boolQueryBuilder.must(rangeQueryBuilder);
} else if (isNumberAndYaxis(astNode.getValue())){
firstLastIndexIsYaxis(astNode.getValue());
for (String str : astNode.getValue().split("\\|")){
boolQueryBuilder.should(QueryBuilders.termQuery(astNode.getKey(), str));
}
} else if (astNode.getValue().equals("*")){
boolQueryBuilder.must(QueryBuilders.existsQuery(astNode.getKey()));
} else if (astNode.getValue().equals("!*")){
boolQueryBuilder.mustNot(QueryBuilders.existsQuery(astNode.getKey()));
} else {
boolQueryBuilder.must(QueryBuilders.matchQuery(astNode.getKey(), astNode.getValue()).operator(org.elasticsearch.index.query.Operator.AND));
}
} else if (operator == Operator.NOT_EQUAL){
if (isNumber(astNode.getValue())){
boolQueryBuilder.mustNot(QueryBuilders.termQuery(astNode.getKey(), astNode.getValue()));
} else if (isNumberOne_(astNode.getValue())){
firstLastIndexIs_(astNode.getValue());
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.from(astNode.getValue().split("_")[0])
.to(astNode.getValue().split("_")[1])
.includeLower(true);
boolQueryBuilder.mustNot(rangeQueryBuilder);
} else if (isNumberAndYaxis(astNode.getValue())){
firstLastIndexIsYaxis(astNode.getValue());
for (String str : astNode.getValue().split("\\|")){
boolQueryBuilder.mustNot(QueryBuilders.termQuery(astNode.getKey(), str));
}
} else if (astNode.getValue().equals("*")){
throw new RuntimeException("filter is error");
} else if (astNode.getValue().equals("!*")){
throw new RuntimeException("filter is error");
} else {
boolQueryBuilder.mustNot(QueryBuilders.matchQuery(astNode.getKey(), astNode.getValue()).operator(org.elasticsearch.index.query.Operator.AND));
}
} else if (operator == Operator.GT){
if (!isNumber(astNode.getValue())){
throw new RuntimeException("filter is error");
}
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.gt(astNode.getValue())
.includeLower(false);
boolQueryBuilder.must(rangeQueryBuilder);
} else if (operator == Operator.GTE){
if (!isNumber(astNode.getValue())){
throw new RuntimeException("filter is error");
}
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.gt(astNode.getValue())
.includeLower(true);
boolQueryBuilder.must(rangeQueryBuilder);
} else if (operator == Operator.LT){
if (!isNumber(astNode.getValue())){
throw new RuntimeException("filter is error");
}
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.lt(astNode.getValue())
.includeUpper(false);
boolQueryBuilder.must(rangeQueryBuilder);
} else if (operator == Operator.LTE){
if (!isNumber(astNode.getValue())){
throw new RuntimeException("filter is error");
}
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(astNode.getKey())
.lt(astNode.getValue())
.includeUpper(true);
boolQueryBuilder.must(rangeQueryBuilder);
}
return;
}
if (astNode.getOperator().getText().equals("&")){
BoolQueryBuilder boolQueryBuilderLeft = new BoolQueryBuilder();
BoolQueryBuilder boolQueryBuilderRight = new BoolQueryBuilder();
boolQueryBuilder.must(boolQueryBuilderLeft)
.must(boolQueryBuilderRight);
preOrder(astNode.getLeft(), boolQueryBuilderLeft, sortAndScroll);
preOrder(astNode.getRight(), boolQueryBuilderRight, sortAndScroll);
} else {
BoolQueryBuilder boolQueryBuilderLeft = new BoolQueryBuilder();
BoolQueryBuilder boolQueryBuilderRight = new BoolQueryBuilder();
boolQueryBuilder.should(boolQueryBuilderLeft)
.should(boolQueryBuilderRight);
preOrder(astNode.getLeft(), boolQueryBuilderLeft, sortAndScroll);
preOrder(astNode.getRight(), boolQueryBuilderRight, sortAndScroll);
}
}
private int getPriority(Token token){
Operator operator = Operator.get(token.getText());
return operator.getPriority();
}
private boolean isNumber(String str){
char[] chars = str.toCharArray();
for (char c : chars){
if ((c >= '0' && c <= '9') || c == '.'){
continue;
} else {
return false;
}
}
return true;
}
public static boolean isNumberOne_(String str){
int count = 0;
char[] chars = str.toCharArray();
for (char c : chars){
if (count > 1){
return false;
//添加支持小数点
} else if ((c >= '0' && c <= '9') || c == '.'){
continue;
} else if (c == '_'){
count++;
continue;
} else {
return false;
}
}
if (count == 1){
return true;
} else {
return false;
}
}
public static boolean isNumberAndYaxis(String str){
char[] chars = str.toCharArray();
for (char c : chars){
if ((c >= '0' && c <= '9') || c == '.'){
continue;
} else if (c == '|'){
continue;
} else {
return false;
}
}
return true;
}
public void firstLastIndexIsYaxis(String str){
if (str.charAt(0) == '|') {
throw new RuntimeException("filter is error");
}
if (str.charAt(str.length()-1) == '|'){
throw new RuntimeException("filter is error");
}
}
public void firstLastIndexIs_(String str){
if (str.charAt(0) == '_'){
throw new RuntimeException("filter is error");
}
if (str.charAt(str.length()-1) == '_'){
throw new RuntimeException("filter is error");
}
}
private String printASTNode(AstNode astNode, int level){
if (!astNode.isReference()){
return astNode.getKey() + astNode.getOperator().getText() + astNode.getValue();
} else {
return getSpace(level+1) + printASTNode(astNode.getRight(), level+1) + "\r\n"
+ getSpace(level) + astNode.getOperator().getText() + "\r\n"
+ getSpace(level+1) + printASTNode(astNode.getLeft(), level+1)+ "\r\n";
}
}
private String getSpace(int n){
if (n == 0){
return "";
} else {
return "------" + getSpace(n-1);
}
}
private void printFilter(String filter) throws IOException {
//1.去掉空格
String f1 = filter.replaceAll(" ", "");
filter = f1;
if (filter.length() > 255){
throw new RuntimeException("filter is too long");
}
//括号是否匹配
parenthesisCheck(filter);
//page和size是否同时出现
pageSizeCheck(filter);
TokenReader tokenReader = new TokenReader(filter);
List<Token> tokens = tokenReader.getTokens();
AstNode astNode = transferAst(tokens);
String s = printASTNode(astNode, 0);
System.out.println(s);
}
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.11.1</version>
<scope>provided</scope>
</dependency>
<!--<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>7.11.1</version>
</dependency>-->
</dependencies>