diff --git a/README.md b/README.md
index 0ec8d4ee..90d520ca 100644
--- a/README.md
+++ b/README.md
@@ -153,5 +153,3 @@ http://localhost:9200/_sql/_explain?sql=select * from indexName limit 10
* ES GEO_DISTANCE
* ES GEOHASH_GRID aggregation
-
-
diff --git a/es-sql.md b/es-sql.md
new file mode 100644
index 00000000..2af83aa9
--- /dev/null
+++ b/es-sql.md
@@ -0,0 +1,176 @@
+# es-sql
+
+## 编译和安装
+
+### 编译
+
+ mvn clean package assembly:single -DskipTests
+
+### 安装方法:
+
+ unzip elasticsearch-sql-2.3.1.1.zip
+ mv elasticsearch-sql-2.3.1.1 sql
+ rm elasticsearch-sql-2.3.1.1.zip
+
+或者
+
+ ./bin/plugin -u file:///home/omershelef/IdeaProjects/elasticsearch-sql/target/elasticsearch-sql-1.3.2.zip --install sql
+
+### es启动方法:
+
+ ../bin/elasticsearch -Des.security.manager.enabled=false
+
+
+## 特性
+
+### SQL 特性
+
+ * SQL Select
+ * SQL Where
+ * SQL Order By
+ * SQL Group By
+ * SQL AND & OR
+ * SQL Like
+ * SQL COUNT distinct
+ * SQL In
+ * SQL Between
+ * SQL Aliases
+ * SQL Not Null
+ * SQL(ES) Date
+ * SQL avg()
+ * SQL count()
+ * SQL last()
+ * SQL max()
+ * SQL min()
+ * SQL sum()
+ * SQL Nulls
+ * SQL isnull()
+ * SQL now()
+
+
+## 增强SQL特性
+
+ * ES nested
+ * ES seg
+ * ES TopHits
+ * ES MISSING
+ * ES STATS
+ * ES GEO_INTERSECTS
+ * ES GEO_BOUNDING_BOX
+ * ES GEO_DISTANCE
+ * ES GEOHASH_GRID aggregation
+
+
+## 接口说明:
+
+### 解析sql 2 sql 接口:
+
+ http://192.168.25.11:9688/_sql/_seg?sql=select * from test where province="河北省"
+
+
+### 解析sql 2 es 接口:
+
+ http://localhost:9200/_sql/_explain?sql=select * from indexName limit 10
+
+### 执行sql地址:
+
+ http://localhost:9200/_sql?sql=select * from indexName limit 10
+
+### UI
+
+ http://192.168.25.11:9688/_plugin/sql/
+
+## 例子:
+
+### 不使用函数
+
+当不使用任何的函数时,默认是使用的match查询,match则会进行分析器处理,分析器中的分词器会将搜索关键字分割成单独的词(terms)或者标记(tokens) 。
+该match的type是phrase,phrase表示确切的匹配若干个单词或短语, 如title: “brown dog”, 则查询title中包含brown和dog, 且两个是连接在一起的
+
+例子:
+
+ SELECT * FROM test_csdn_user_profile_12_201512_v4 where title = "brown dog"
+
+### matchQuery()
+
+matchQuery()使用的type是boolean。
+函数中可指定两个参数,不可指定operator和minimum_should_match,除了可以指定分词器外,和不使用函数没有区别:
+
+* 第一个参数是:查询词
+* 第二个参数是:analyzer,有三个值可供选择:query_ansj、dic_ansj、index_ansj
+
+例子:
+
+ select * from user_metric where province = matchQuery("河北")
+
+
+### term()
+
+term查找时内容精确匹配,只有一个参数,即需要查询的词
+
+例子:
+
+ select * from user_metric where province = term("河北")
+
+### IN_TERMS()
+
+在函数中可以指定多个词,进行查询
+
+例子:
+
+ SELECT * FROM test_csdn_user_profile_12_201512_v4 where province = IN_TERMS("河北省","北京市")
+
+
+### 根据Id查询 IDS_QUERY()
+
+可指定多个id进行查询,函数中第一个参数是type,后边是需要指定的id,对于type加不加双引号均可
+
+例子:
+
+ select * from %s/dog where _id = IDS_QUERY(dog,1,2,3)
+ SELECT * FROM test_csdn_user_profile_12_201512_v4 where _id = IDS_QUERY("user","azjw1989","jslp1990")
+
+### 模糊匹配 like
+
+* *和%代表任意个字符(包括空字符)
+* ?问号是单个字符
+请注意,此查询可能很慢,因为它需要迭代许多项。 为了防止极慢的通配符查询,通配符术语不应以通配符*或?开头。
+
+例子:
+
+ SELECT * FROM user_metric WHERE province LIKE "邯郸%%"
+
+### in
+
+使用match进行多个值查询,各个值间是或的关系
+
+例子:
+
+ SELECT * FROM user_profile_12_201512_v4 where province in ("河北省","北京市")
+
+### 嵌套类型 nested()
+
+nested方法可在where和order by中使用。
+在where中有两个参数:
+* 第一个参数是:父field
+* 第二个参数是:子filed的表达式
+
+在order by中有三个参数:
+* 第一个参数是:父field
+* 第二个参数是:指定排序字段,以及排序函数,可使用sum、min、max、avg四个函数
+* 第三个参数是:子filed的表达式
+
+例子:
+
+ SELECT * FROM elasticsearch-sql_test_index where nested(message,message.info=term("c")) and nested(message,message.info=term("a")) order by nested(message, sum(message.dayOfWeek),message.info=term("a") and message.info=term("c")) desc
+
+### object对象
+
+非嵌套的object,直接使用 父field.子field 即可查询
+
+例子:
+ SELECT * FROM elasticsearch-sql_test_index where message.info=term("c")
+
+
+http://192.168.25.11:9688/_sql/_seg?sql=select%20*%20from%20awhere nested(a,(a.b="x" or a.b=seg"y")and a.b=seg"z")
+
diff --git a/pom.xml b/pom.xml
index 2c3f4ddd..fb020fe4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.nlpcn
elasticsearch-sql
- 2.3.1.1
+ 2.3.1.2
jar
Query elasticsearch using SQL
elasticsearch-sql
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java b/src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java
index e5d5fe28..9ec0fb38 100644
--- a/src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java
@@ -5,10 +5,11 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugin.nlpcn.executors.ActionRequestRestExecuterFactory;
import org.elasticsearch.plugin.nlpcn.executors.RestExecutor;
+import org.elasticsearch.plugin.nlpcn.preAnalyzer.AnsjAnalyzerImpl;
+import org.elasticsearch.plugin.nlpcn.preAnalyzer.SqlParseAnalyzer;
import org.elasticsearch.rest.*;
import org.nlpcn.es4sql.SearchDao;
import org.nlpcn.es4sql.query.QueryAction;
-import org.nlpcn.es4sql.query.SqlElasticRequestBuilder;
import java.util.Map;
@@ -22,6 +23,7 @@ public RestSqlAction(Settings settings, Client client, RestController restContro
restController.registerHandler(RestRequest.Method.GET, "/_sql/_explain", this);
restController.registerHandler(RestRequest.Method.POST, "/_sql", this);
restController.registerHandler(RestRequest.Method.GET, "/_sql", this);
+ restController.registerHandler(RestRequest.Method.GET, "/_sql/_seg", this);
}
@Override
@@ -31,11 +33,17 @@ protected void handleRequest(RestRequest request, RestChannel channel, final Cli
if (sql == null) {
sql = request.content().toUtf8();
}
+ //ananlyze
+ SqlParseAnalyzer sqlParseAnalyzer = new SqlParseAnalyzer(new AnsjAnalyzerImpl());
+ sql = sqlParseAnalyzer.seg(sql);
SearchDao searchDao = new SearchDao(client);
QueryAction queryAction= searchDao.explain(sql);
// TODO add unittests to explain. (rest level?)
- if (request.path().endsWith("/_explain")) {
+ if(request.path().endsWith("_seg")){
+ BytesRestResponse bytesRestResponse = new BytesRestResponse(RestStatus.OK, sql);
+ channel.sendResponse(bytesRestResponse);
+ } else if (request.path().endsWith("/_explain")) {
String jsonExplanation = queryAction.explain().explain();
BytesRestResponse bytesRestResponse = new BytesRestResponse(RestStatus.OK, jsonExplanation);
channel.sendResponse(bytesRestResponse);
@@ -45,4 +53,4 @@ protected void handleRequest(RestRequest request, RestChannel channel, final Cli
restExecutor.execute(client,params,queryAction,channel);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/SqlPlug.java b/src/main/java/org/elasticsearch/plugin/nlpcn/SqlPlug.java
index ad1fb096..a27350d0 100644
--- a/src/main/java/org/elasticsearch/plugin/nlpcn/SqlPlug.java
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/SqlPlug.java
@@ -1,9 +1,15 @@
package org.elasticsearch.plugin.nlpcn;
+import org.elasticsearch.common.inject.AbstractModule;
+import org.elasticsearch.common.inject.Module;
+import org.elasticsearch.plugin.nlpcn.preAnalyzer.AnsjAnalyzerAction;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestModule;
+import java.util.Collection;
+import java.util.Collections;
+
public class SqlPlug extends Plugin {
public SqlPlug() {
@@ -18,6 +24,16 @@ public String name() {
public String description() {
return "Use sql to query elasticsearch.";
}
+ @Override
+ public Collection nodeModules() {
+ return Collections. singletonList(new AnsjModule());
+ }
+ public static class AnsjModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(AnsjAnalyzerAction.class).asEagerSingleton();
+ }
+ }
public void onModule(RestModule module)
{
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Analyzer.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Analyzer.java
new file mode 100644
index 00000000..43f2da9a
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Analyzer.java
@@ -0,0 +1,8 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+/**
+ * Created by linxueqing on 2016/12/13.
+ */
+public interface Analyzer {
+ public String[] analyzer(String term) throws Exception;
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerAction.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerAction.java
new file mode 100644
index 00000000..0338c203
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerAction.java
@@ -0,0 +1,16 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+import org.elasticsearch.common.component.AbstractComponent;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.settings.Settings;
+
+/**
+ * Created by fangbb on 2016-12-6.
+ */
+public class AnsjAnalyzerAction extends AbstractComponent {
+ @Inject
+ public AnsjAnalyzerAction(final Settings settings){
+ super(settings);
+ AnsjElasticConfigurator.init(settings);
+ }
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerImpl.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerImpl.java
new file mode 100644
index 00000000..289e3793
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjAnalyzerImpl.java
@@ -0,0 +1,61 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+import org.elasticsearch.plugin.nlpcn.request.HttpRequester;
+import org.elasticsearch.plugin.nlpcn.request.HttpResponse;
+
+import java.net.URLEncoder;
+
+/**
+ * Created by fangbb on 2016-12-12.
+ */
+public class AnsjAnalyzerImpl implements Analyzer {
+
+ public String[] analyzer(String term) throws Exception {
+ //TODO done
+ HttpRequester request = new HttpRequester();
+ HttpResponse response = null;
+ String sourceTerms = "";
+// http://192.168.25.11:9688/_cat/analyze?text=大数据&analyzer=query_ansj
+ try {
+ //String ip = InetAddress.getLocalHost().getHostAddress();
+ String ip = AnsjElasticConfigurator.ES_IP;
+ String port = AnsjElasticConfigurator.ES_PORT;
+ String midUrl = "/_cat/analyze?analyzer=query_ansj&text=";
+ String preUrl = "http://" + ip + ":" + port + midUrl;
+ //String preUrl = "http://192.168.25.11:9688/_cat/analyze?analyzer=query_ansj&text=";
+ //System.out.println(preUrl);
+ String enTerm = URLEncoder.encode(term, "UTF-8");
+ String url = preUrl + enTerm;
+ //System.out.println(url);
+ response = request.sendGet(url);
+ if (response.getCode() == 200) {
+ if (response != null && response.getContent().length() > 10) {
+ sourceTerms = response.getContent();
+ }
+ }
+
+ } catch (Exception e) {
+ throw new Exception("There is an error in the word segmentation");
+ }
+ return getTerms(sourceTerms).split(",");
+ }
+
+ private static String getTerms(String sourceTerms) {
+ StringBuffer sb = new StringBuffer();
+ String[] lines = sourceTerms.split("\n");
+ int lineLen = lines.length;
+ for (int i = 0; i < lineLen; i++) {
+ String[] terms = lines[i].split("\t");
+ String term = terms[0].trim();
+ int size = terms.length;
+ if (i == 0) {
+ //sb.append("\"").append(term).append("\"");
+ sb.append(term);
+ } else {
+ sb.append(",").append(term);
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjElasticConfigurator.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjElasticConfigurator.java
new file mode 100644
index 00000000..a8c5bcff
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/AnsjElasticConfigurator.java
@@ -0,0 +1,37 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.Loggers;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.env.Environment;
+
+/**
+ * Created by fangbb on 2016-11-25.
+ */
+public class AnsjElasticConfigurator {
+ public static ESLogger logger = Loggers.getLogger("sql-init");
+ public static Environment environment;
+ public static String ES_IP = "";
+ public static String ES_PORT = "";
+
+ public static void init(Settings settings) {
+ try {
+ ES_IP = settings.get("network.host");
+ ES_PORT = settings.get("http.port");
+ if (ES_IP == null || ES_IP.equals("")) {
+ logger.error("network.host获取失败");
+ } else {
+ logger.info("network.host:" + ES_IP);
+ }
+ if (ES_PORT == null || ES_PORT.equals("")) {
+ ES_PORT = "9200";
+ logger.error("http.port获取失败,使用默认端口:9200");
+ } else {
+ logger.info("http.port:"+ ES_PORT);
+ }
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Method.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Method.java
new file mode 100644
index 00000000..fd3ca88d
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/Method.java
@@ -0,0 +1,66 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+/**
+ * Created by fangbb on 2016-12-8.
+ */
+public class Method {
+ String parentMethod;
+ String childenMethod;
+ String params;
+
+ public Method(String parentMethod, String childenMethod, String params) {
+ this.parentMethod = parentMethod;
+ this.childenMethod = childenMethod;
+ this.params = params;
+ }
+
+ public Method() {
+ }
+
+ public String getParentMethod() {
+ return parentMethod;
+ }
+
+ public void setParentMethod(String parentMethod) {
+ this.parentMethod = parentMethod;
+ }
+
+ public String getChildenMethod() {
+ return childenMethod;
+ }
+
+ public void setChildenMethod(String childenMethod) throws Exception{
+ if (this.parentMethod.equals("seg") && childenMethod != null) {
+ throw new Exception("seg("+childenMethod+"()) is erro");
+ } else {
+ this.childenMethod = childenMethod;
+ }
+
+ }
+
+ public String getParams() {
+ return params;
+ }
+
+ public void setParams(String params) {
+ this.params = params;
+ }
+
+ public String getFunName() {
+ String name = "";
+ if (this.parentMethod != null && !this.parentMethod.equals("seg")) {
+ name = this.parentMethod;
+ } else if (this.childenMethod != null && !this.childenMethod.equals("seg")) {
+ name = this.childenMethod;
+ }
+ return name;
+ }
+
+ public boolean containSeg() {
+ if (this.parentMethod != null && this.parentMethod.equals("seg")
+ ||this.childenMethod!=null && this.childenMethod.equals("seg")) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/SqlParseAnalyzer.java b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/SqlParseAnalyzer.java
new file mode 100644
index 00000000..0af7031f
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/preAnalyzer/SqlParseAnalyzer.java
@@ -0,0 +1,420 @@
+package org.elasticsearch.plugin.nlpcn.preAnalyzer;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.SQLObject;
+import com.alibaba.druid.sql.ast.SQLOrderBy;
+import com.alibaba.druid.sql.ast.expr.*;
+import com.alibaba.druid.sql.ast.statement.SQLSelect;
+import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
+import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
+import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
+import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
+import com.alibaba.druid.util.JdbcConstants;
+import org.nlpcn.es4sql.parse.ElasticLexer;
+import org.nlpcn.es4sql.parse.ElasticSqlExprParser;
+
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Created by fangbb on 2016-12-6.
+ */
+public class SqlParseAnalyzer {
+// public String dbType = JdbcConstants.MYSQL;
+ private Analyzer analyzer;
+
+ public SqlParseAnalyzer(Analyzer analyzer) {
+ this.analyzer = analyzer;
+ }
+
+ public String seg(String sql) throws Exception {
+ if (sql.contains("seg(")) {
+ MySqlSelectQueryBlock query = getQueryBlock(sql);
+ parseWhere(query.getWhere());
+ parseOrderBys(query.getOrderBy());
+ sql = printSql(query);
+ }
+ return sql;
+ }
+
+ private MySqlSelectQueryBlock getQueryBlock(String sql) {
+ ElasticLexer lexer = new ElasticLexer(sql);
+ lexer.nextToken();
+ ElasticSqlExprParser elasticSqlExprParser = new ElasticSqlExprParser(lexer);
+ SQLExpr expr = elasticSqlExprParser.expr();
+ SQLQueryExpr sqlExpr = (SQLQueryExpr) expr;
+ SQLSelect sqlSelect = sqlExpr.getSubQuery();
+ //获取SQLSelectQuery
+ SQLSelectQuery sqlSelectQuery = sqlSelect.getQuery();
+ MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) sqlSelectQuery;
+ return query;
+ }
+
+ private void parseWhere(SQLExpr where) throws Exception {
+ if (where == null) {
+ return;
+ }
+ preTraverse(where);
+ }
+
+ private void parseOrderBys(SQLOrderBy sqlOrderBy) throws Exception {
+ if (sqlOrderBy == null) {
+ return;
+ }
+ List items = sqlOrderBy.getItems();
+ for (SQLSelectOrderByItem item : items) {
+ SQLExpr sqlExpr = item.getExpr();
+ if (sqlExpr instanceof SQLMethodInvokeExpr) {
+ String nested = ((SQLMethodInvokeExpr) sqlExpr).getMethodName();
+ List params = ((SQLMethodInvokeExpr) sqlExpr).getParameters();
+ if (nested.equals("nested") && params.size() == 3) {
+ parseWhere(params.get(2));
+ } else {
+ throw new Exception("Nested sorting must be 3 parameters");
+ }
+ }
+ }
+ }
+
+ //先序遍历获取叶子节点
+ private void preTraverse(SQLExpr sqlExpr) throws Exception {
+ if (sqlExpr instanceof SQLBinaryOpExpr) {
+ SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) sqlExpr;
+ SQLExpr left = sqlBinaryOpExpr.getLeft();
+ SQLExpr right = sqlBinaryOpExpr.getRight();
+ SQLBinaryOperator sqlBinaryOperator = sqlBinaryOpExpr.getOperator();
+ if (isLeaf(sqlBinaryOperator)) {
+ // 普通叶节点替换
+ replaceLeafNode(sqlBinaryOpExpr);
+ } else {
+ preTraverse(left);
+ preTraverse(right);
+ }
+ } else if (isNested(sqlExpr)) {
+ //nested 嵌套叶节点
+ replaceNestedLeafNode(sqlExpr);
+ } else {
+ throw new SQLFeatureNotSupportedException();
+ }
+ }
+
+ //TODO 对Nested叶节点拆分
+ //TODO 分词
+ //TODO 构造新节点
+ private void replaceNestedLeafNode(SQLExpr sqlExpr) throws Exception {
+ SQLObject sqlObject = sqlExpr.getParent();
+ SQLExpr newExpr = parseNested(sqlExpr);
+ if (sqlObject instanceof MySqlSelectQueryBlock) {
+ ((MySqlSelectQueryBlock) sqlObject).setWhere(newExpr);
+ } else if (sqlObject instanceof SQLBinaryOpExpr) {
+ if (sqlExpr.equals(((SQLBinaryOpExpr) sqlObject).getRight())) {
+ ((SQLBinaryOpExpr) sqlObject).setRight(newExpr);
+ } else {
+ ((SQLBinaryOpExpr) sqlObject).setLeft(newExpr);
+ }
+ }
+ }
+
+ //TODO 解析nested的叶节点,返回新构造的叶节点
+ private SQLExpr parseNested(SQLExpr sqlExpr) throws Exception {
+ String methodName = ((SQLMethodInvokeExpr) sqlExpr).getMethodName();
+ if (((SQLMethodInvokeExpr) sqlExpr).getParameters().size() != 2) {
+ throw new Exception("Nested query must be 2 parameters");
+ }
+ SQLExpr pathName = ((SQLMethodInvokeExpr) sqlExpr).getParameters().get(0);
+ SQLExpr where = ((SQLMethodInvokeExpr) sqlExpr).getParameters().get(1);
+ SQLExpr retExpr = null;
+ if (where != null) {
+ preTraverseNested(methodName, pathName, where);
+ if (isLeaf(where)) {
+ SQLObject parent = where.getParent();
+ if (parent instanceof SQLMethodInvokeExpr) {
+ SQLMethodInvokeExpr tmp = ((SQLMethodInvokeExpr) parent);
+ if (tmp.getParameters().size() == 3) {
+ retExpr = tmp.getParameters().get(2);
+ } else {
+ retExpr = tmp;
+ }
+ }
+ } else if (where instanceof SQLBinaryOpExpr) {
+ retExpr = where;
+ }
+
+ }
+ return retExpr;
+ }
+
+ private void preTraverseNested(String methodName, SQLExpr pathName, SQLExpr sqlExpr) throws Exception {
+ if (sqlExpr instanceof SQLBinaryOpExpr) {
+ SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) sqlExpr;
+ SQLExpr left = sqlBinaryOpExpr.getLeft();
+ SQLExpr right = sqlBinaryOpExpr.getRight();
+ SQLBinaryOperator sqlBinaryOperator = sqlBinaryOpExpr.getOperator();
+ //left和right都是a=b这种形式
+ if (isLeaf(sqlBinaryOperator)) {
+ generateNestedLeafNode(methodName, pathName, sqlBinaryOpExpr);
+ } else {
+ preTraverseNested(methodName, pathName, left);
+ preTraverseNested(methodName, pathName, right);
+ }
+ }
+ }
+
+ private boolean isNested(SQLExpr sqlExpr) {
+ if (sqlExpr instanceof SQLMethodInvokeExpr) {
+ String mName = ((SQLMethodInvokeExpr) sqlExpr).getMethodName();
+ if (mName.equals("nested")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isLeaf(SQLBinaryOperator sqlBinaryOperator) {
+ if (sqlBinaryOperator.equals(SQLBinaryOperator.BooleanOr) || sqlBinaryOperator.equals(SQLBinaryOperator.BooleanAnd)) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isLeaf(SQLExpr sqlExpr) {
+ if (sqlExpr instanceof SQLBinaryOpExpr) {
+ SQLBinaryOperator sqlBinaryOperator = ((SQLBinaryOpExpr) sqlExpr).getOperator();
+ if (sqlBinaryOperator.equals(SQLBinaryOperator.BooleanOr) || sqlBinaryOperator.equals(SQLBinaryOperator.BooleanAnd)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private Method parseMethod(SQLExpr right) throws Exception {
+ Method retMethod = new Method();
+ if (right instanceof SQLMethodInvokeExpr) {
+ SQLMethodInvokeExpr methodInvokeExpr = ((SQLMethodInvokeExpr) right);
+ String methodName = methodInvokeExpr.getMethodName();
+ retMethod.setParentMethod(methodName);
+ List childMethod = methodInvokeExpr.getParameters();
+ SQLExpr sqlExpr = childMethod.get(0);
+ if (sqlExpr instanceof SQLMethodInvokeExpr) {
+ retMethod.setChildenMethod(((SQLMethodInvokeExpr) sqlExpr).getMethodName());
+ SQLExpr nSqlExpr = ((SQLMethodInvokeExpr) sqlExpr).getParameters().get(0);
+ if (nSqlExpr instanceof SQLCharExpr) {
+ retMethod.setParams(((SQLCharExpr) nSqlExpr).getText());
+ } else if (nSqlExpr instanceof SQLIdentifierExpr) {
+ if (retMethod.getChildenMethod().equals("seg")) {
+ SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr) nSqlExpr;
+ retMethod.setParams(identifierExpr.getName());
+ childMethod.clear();
+ childMethod.add(0, identifierExpr);
+ retMethod.setChildenMethod(null);
+ }
+ }
+ } else if (sqlExpr instanceof SQLCharExpr) {
+ retMethod.setParams(((SQLCharExpr) sqlExpr).getText());
+ } else if (sqlExpr instanceof SQLIdentifierExpr) {
+ retMethod.setParams(((SQLIdentifierExpr) sqlExpr).getName());
+ }
+ }
+ return retMethod;
+ }
+
+ private boolean segNoQuota(SQLMethodInvokeExpr methodInvokeExpr) {
+ List params = methodInvokeExpr.getParameters();
+ if (params.get(0) instanceof SQLIdentifierExpr) {
+ return true;
+ }
+ return false;
+ }
+
+ private void removeSegFun(SQLBinaryOpExpr binaryOpExpr, SQLExpr right, Method method) {
+ //当seg内没有引号时,去掉seg()
+ if (segNoQuota((SQLMethodInvokeExpr) right) && method.containSeg()) {
+ method.setParentMethod(null);
+ List params = ((SQLMethodInvokeExpr) right).getParameters();
+ binaryOpExpr.setRight(params.get(0));
+ }
+ }
+
+ private void generateNestedLeafNode(String methodName, SQLExpr pathName, SQLBinaryOpExpr binaryOpExpr) throws Exception {
+ //right:a.b = "d"
+ SQLExpr left = binaryOpExpr.getLeft();
+ SQLExpr right = binaryOpExpr.getRight();
+ SQLBinaryOperator operator = binaryOpExpr.getOperator();
+ String filed = ((SQLIdentifierExpr) left).getName();
+ if (right instanceof SQLMethodInvokeExpr) {
+ Method method = parseMethod(right);
+ String sourceTerm = method.getParams();
+ removeSegFun(binaryOpExpr, right, method);
+ //seg(term("abc")) exception
+ if (method.containSeg() && sourceTerm != null) {
+ String[] terms = analyzer.analyzer(sourceTerm);
+ //String[] terms = "a,b".split(",");
+ String funName = method.getFunName();
+ List allNewNode = new ArrayList();
+ for (String term : terms) {
+ if (!funName.equals("")) {
+ SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr();
+ methodInvokeExpr.setMethodName(funName);
+ methodInvokeExpr.addParameter(new SQLCharExpr(term));
+ SQLBinaryOpExpr opNode = createOpNode(filed, methodInvokeExpr, operator);
+ SQLMethodInvokeExpr nestedNode = createNestedNode(methodName, pathName, opNode);
+ allNewNode.add(nestedNode);
+ } else {
+ SQLCharExpr charExpr = new SQLCharExpr();
+ charExpr.setText(term);
+ SQLBinaryOpExpr opNode = createOpNode(filed, charExpr, operator);
+ SQLMethodInvokeExpr nestedNode = createNestedNode(methodName, pathName, opNode);
+ allNewNode.add(nestedNode);
+ }
+ }
+ conNestedTree(binaryOpExpr, allNewNode);
+ } else {
+ List allNewNode = new ArrayList();
+ SQLBinaryOpExpr opNode = createOpNode(filed, right, operator);
+ SQLMethodInvokeExpr nestedNode = createNestedNode(methodName, pathName, opNode);
+ allNewNode.add(nestedNode);
+ conNestedTree(binaryOpExpr, allNewNode);
+ }
+ } else {
+ List allNewNode = new ArrayList();
+ SQLBinaryOpExpr opNode = createOpNode(filed, right, operator);
+ SQLMethodInvokeExpr nestedNode = createNestedNode(methodName, pathName, opNode);
+ allNewNode.add(nestedNode);
+ conNestedTree(binaryOpExpr, allNewNode);
+ }
+ }
+
+ private void replaceOldNode(SQLExpr sqlExpr,SQLExpr newExpr) throws Exception {
+ SQLObject sqlObject = sqlExpr.getParent();
+ if (sqlObject instanceof MySqlSelectQueryBlock) {
+ ((MySqlSelectQueryBlock) sqlObject).setWhere(newExpr);
+ } else if (sqlObject instanceof SQLBinaryOpExpr) {
+ if (sqlExpr.equals(((SQLBinaryOpExpr) sqlObject).getRight())) {
+ ((SQLBinaryOpExpr) sqlObject).setRight(newExpr);
+ } else {
+ ((SQLBinaryOpExpr) sqlObject).setLeft(newExpr);
+ }
+ } else if (sqlObject instanceof SQLMethodInvokeExpr) {
+ ((SQLMethodInvokeExpr) sqlObject).addParameter(newExpr);
+ }
+ }
+
+ //构造新的二叉树替换原有节点
+ private void conNestedTree(SQLBinaryOpExpr retExpr, List sqlExprs) throws Exception{
+ int size = sqlExprs.size();
+ int andNum = size - 1;
+ List allNode = new ArrayList();
+ if (andNum == 0) {
+ replaceOldNode(retExpr, sqlExprs.get(0));
+ } else {
+ for (int i = 0; i < andNum; i++) {
+ if (i == 0) {
+ retExpr.setOperator(SQLBinaryOperator.BooleanAnd);
+ //retExpr做为顶点
+ allNode.add(retExpr);
+ } else {
+ allNode.add(createOpNode(null, null, SQLBinaryOperator.BooleanAnd));
+ }
+ }
+ allNode.addAll(sqlExprs);
+ //共有n-1个And,n个node,每一个节点从0开始进行编号,那么第i个节点的左孩子的编号为2*i+1,右孩子为2*i+2。
+ for (int parentIndex = 0; parentIndex < andNum; parentIndex++) {
+ if (allNode.get(parentIndex) instanceof SQLBinaryOpExpr) {
+ ((SQLBinaryOpExpr) allNode.get(parentIndex)).setLeft(allNode.get(parentIndex * 2 + 1));
+ ((SQLBinaryOpExpr) allNode.get(parentIndex)).setRight(allNode.get(parentIndex * 2 + 2));
+ }
+ }
+ }
+ }
+
+ //对叶节点分词,构造新节点
+ private void replaceLeafNode(SQLBinaryOpExpr binaryOpExpr) throws Exception {
+ SQLExpr left = binaryOpExpr.getLeft();
+ SQLExpr right = binaryOpExpr.getRight();
+ SQLBinaryOperator operator = binaryOpExpr.getOperator();
+ String filed = ((SQLIdentifierExpr) left).getName();
+ if (right instanceof SQLMethodInvokeExpr) {
+ Method method = parseMethod(right);
+ String sourceTerm = method.getParams();
+ removeSegFun(binaryOpExpr, right, method);
+ //seg(term("abc")) exception
+ if (method.containSeg() && sourceTerm != null) {
+ String[] terms = analyzer.analyzer(sourceTerm);
+ //String[] terms = "a,b".split(",");
+ String funName = method.getFunName();
+ List allNewNode = new ArrayList();
+ for (String term : terms) {
+ if (!funName.equals("")) {
+ SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr();
+ methodInvokeExpr.setMethodName(funName);
+ methodInvokeExpr.addParameter(new SQLCharExpr(term));
+ allNewNode.add(createOpNode(filed, methodInvokeExpr, operator));
+ } else {
+ SQLCharExpr charExpr = new SQLCharExpr();
+ charExpr.setText(term);
+ allNewNode.add(createOpNode(filed, charExpr, operator));
+ }
+
+ }
+ conTree(binaryOpExpr, allNewNode);
+ }
+ }
+ }
+
+ //构造新的二叉树替换原有节点
+ private void conTree(SQLBinaryOpExpr retExpr, List SQLBinaryOpNode) {
+ int size = SQLBinaryOpNode.size();
+ int andNum = size - 1;
+ List allNode = new ArrayList();
+ if (andNum == 0) {
+ retExpr.setRight(SQLBinaryOpNode.get(0).getRight());
+ } else {
+ for (int i = 0; i < andNum; i++) {
+ if (i == 0) {
+ retExpr.setOperator(SQLBinaryOperator.BooleanAnd);
+ //retExpr做为顶点
+ allNode.add(retExpr);
+ } else {
+ allNode.add(createOpNode(null, null, SQLBinaryOperator.BooleanAnd));
+ }
+ }
+ allNode.addAll(SQLBinaryOpNode);
+ //共有n-1个And,n个node,每一个节点从0开始进行编号,那么第i个节点的左孩子的编号为2*i+1,右孩子为2*i+2。
+ for (int parentIndex = 0; parentIndex < andNum; parentIndex++) {
+ allNode.get(parentIndex).setLeft(allNode.get(parentIndex * 2 + 1));
+ allNode.get(parentIndex).setRight(allNode.get(parentIndex * 2 + 2));
+ }
+ }
+ }
+
+
+ //TODO 构造一个节点
+ private SQLBinaryOpExpr createOpNode(String filed, SQLExpr value, SQLBinaryOperator operator) {
+ SQLBinaryOpExpr retWhere = new SQLBinaryOpExpr();
+ SQLIdentifierExpr ileft = new SQLIdentifierExpr();
+ ileft.setName(filed);
+ retWhere.setLeft(ileft);
+ retWhere.setOperator(operator);
+ retWhere.setRight(value);
+ return retWhere;
+ }
+
+ //TODO 构造一个nested节点
+ private SQLMethodInvokeExpr createNestedNode(String name, SQLExpr pathName, SQLBinaryOpExpr sqlBinaryOpExpr) {
+ SQLMethodInvokeExpr sqlMethodInvokeExpr = new SQLMethodInvokeExpr();
+ sqlMethodInvokeExpr.setMethodName(name);
+ sqlMethodInvokeExpr.addParameter(pathName);
+ sqlMethodInvokeExpr.addParameter(sqlBinaryOpExpr);
+ return sqlMethodInvokeExpr;
+ }
+
+ private String printSql(MySqlSelectQueryBlock query) {
+ StringBuilder out = new StringBuilder();
+ MySqlOutputVisitor visitor = new MySqlOutputVisitor(out);
+ query.accept0(visitor);
+ return out.toString();
+ }
+
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpRequester.java b/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpRequester.java
new file mode 100644
index 00000000..f5e98dc1
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpRequester.java
@@ -0,0 +1,299 @@
+package org.elasticsearch.plugin.nlpcn.request;
+
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * HTTP请求对象
+ *
+ */
+public class HttpRequester {
+
+
+ private String defaultContentEncoding;
+
+ private int defaultTimeout = 5000;
+
+ public HttpRequester() {
+ this.defaultContentEncoding = Charset.defaultCharset().name();
+ }
+
+ /**
+ * 发送GET请求
+ *
+ * @param urlString
+ * URL地址
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendGet(String urlString) throws IOException {
+ return this.send(urlString, "GET", null, null);
+ }
+
+ /**
+ * 发送GET请求
+ *
+ * @param urlString
+ * URL地址
+ * @param params
+ * 参数集合
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendGet(String urlString, Map params)
+ throws IOException {
+ return this.send(urlString, "GET", params, null);
+ }
+
+ /**
+ * 发送GET请求
+ *
+ * @param urlString
+ * URL地址
+ * @param params
+ * 参数集合
+ * @param propertys
+ * 请求属性
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendGet(String urlString, Map params,
+ Map propertys) throws IOException {
+ return this.send(urlString, "GET", params, propertys);
+ }
+
+ /**
+ * 发送POST请求
+ *
+ * @param urlString
+ * URL地址
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendPost(String urlString) throws IOException {
+ return this.send(urlString, "POST", null, null);
+ }
+
+ /**
+ * 发送POST请求
+ *
+ * @param urlString
+ * URL地址
+ * @param params
+ * 参数集合
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendPost(String urlString, Map params)
+ throws IOException {
+ return this.send(urlString, "POST", params, null);
+ }
+
+ /**
+ * 发送POST请求
+ *
+ * @param urlString
+ * URL地址
+ * @param params
+ * 参数集合
+ * @param propertys
+ * 请求属性
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ public HttpResponse sendPost(String urlString, Map params,
+ Map propertys) throws IOException {
+ return this.send(urlString, "POST", params, propertys);
+ }
+
+ /*
+ * POST
+ */
+ public HttpResponse sendPostRawData(String urlString, Map parameters,
+ Map propertys, String rawData) throws IOException {
+
+ String method = "POST";
+
+ HttpURLConnection urlConnection = null;
+
+ if (method.equalsIgnoreCase("POST") && parameters != null) {
+ StringBuffer param = new StringBuffer();
+ int i = 0;
+ for (String key : parameters.keySet()) {
+ if (i == 0)
+ param.append("?");
+ else
+ param.append("&");
+ param.append(key).append("=").append(parameters.get(key));
+ i++;
+ }
+ urlString += param;
+ }
+ URL url = new URL(urlString);
+ urlConnection = (HttpURLConnection) url.openConnection();
+
+ urlConnection.setRequestMethod(method);
+ urlConnection.setDoOutput(true);
+ urlConnection.setDoInput(true);
+ urlConnection.setUseCaches(false);
+ urlConnection.setConnectTimeout(defaultTimeout);
+ urlConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+
+ urlConnection.setRequestProperty("Content-Type", "text/plain;charset=UTF-8");
+
+ if (propertys != null)
+ for (String key : propertys.keySet()) {
+ urlConnection.addRequestProperty(key, propertys.get(key));
+ }
+
+ if (method.equalsIgnoreCase("POST") && rawData != null) {
+
+ OutputStream outStream = urlConnection.getOutputStream();
+ outStream.write(rawData.getBytes());
+
+ outStream.flush();
+ outStream.close();
+ }
+
+ return this.makeContent(urlString, urlConnection);
+ }
+
+ /**
+ * 发送HTTP请求
+ *
+ * @param urlString
+ * @return 响映对象
+ * @throws java.io.IOException
+ */
+ private HttpResponse send(String urlString, String method,
+ Map parameters, Map propertys)
+ throws IOException {
+ HttpURLConnection urlConnection = null;
+
+ if (method.equalsIgnoreCase("GET") && parameters != null) {
+ StringBuffer param = new StringBuffer();
+ int i = 0;
+ for (String key : parameters.keySet()) {
+ if (i == 0)
+ param.append("?");
+ else
+ param.append("&");
+ param.append(key).append("=").append(parameters.get(key));
+ i++;
+ }
+ urlString += param;
+ }
+ URL url = new URL(urlString);
+ urlConnection = (HttpURLConnection) url.openConnection();
+
+ urlConnection.setRequestMethod(method);
+ urlConnection.setDoOutput(true);
+ urlConnection.setDoInput(true);
+ urlConnection.setUseCaches(false);
+ urlConnection.setConnectTimeout(defaultTimeout);
+ urlConnection.setReadTimeout(defaultTimeout*2);
+ urlConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+ if (propertys != null)
+ for (String key : propertys.keySet()) {
+ urlConnection.addRequestProperty(key, propertys.get(key));
+ }
+
+ if (method.equalsIgnoreCase("POST") && parameters != null) {
+ StringBuffer param = new StringBuffer();
+ for (String key : parameters.keySet()) {
+ param.append("&");
+ param.append(key).append("=").append(parameters.get(key));
+ }
+ urlConnection.getOutputStream().write(param.toString().getBytes());
+ urlConnection.getOutputStream().flush();
+ urlConnection.getOutputStream().close();
+ }
+
+ return this.makeContent(urlString, urlConnection);
+ }
+
+ /**
+ * 得到响应对象
+ *
+ * @param urlConnection
+ * @return 响应对象
+ * @throws java.io.IOException
+ */
+ private HttpResponse makeContent(String urlString,
+ HttpURLConnection urlConnection) throws IOException {
+ HttpResponse httpResponser = new HttpResponse();
+ try {
+ InputStream in = urlConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(
+ new InputStreamReader(in));
+ httpResponser.contentCollection = new Vector();
+ StringBuffer temp = new StringBuffer();
+ String line = bufferedReader.readLine();
+ while (line != null) {
+ httpResponser.contentCollection.add(line);
+ temp.append(line).append("\r\n");
+ line = bufferedReader.readLine();
+ }
+ bufferedReader.close();
+
+ String ecod = urlConnection.getContentEncoding();
+ if (ecod == null)
+ ecod = this.defaultContentEncoding;
+
+ httpResponser.urlString = urlString;
+
+ httpResponser.defaultPort = urlConnection.getURL().getDefaultPort();
+ httpResponser.file = urlConnection.getURL().getFile();
+ httpResponser.host = urlConnection.getURL().getHost();
+ httpResponser.path = urlConnection.getURL().getPath();
+ httpResponser.port = urlConnection.getURL().getPort();
+ httpResponser.protocol = urlConnection.getURL().getProtocol();
+ httpResponser.query = urlConnection.getURL().getQuery();
+ httpResponser.ref = urlConnection.getURL().getRef();
+ httpResponser.userInfo = urlConnection.getURL().getUserInfo();
+
+ httpResponser.content = new String(temp.toString().getBytes(), ecod);
+ httpResponser.contentEncoding = ecod;
+ httpResponser.code = urlConnection.getResponseCode();
+ httpResponser.message = urlConnection.getResponseMessage();
+ httpResponser.contentType = urlConnection.getContentType();
+ httpResponser.method = urlConnection.getRequestMethod();
+ httpResponser.connectTimeout = urlConnection.getConnectTimeout();
+ httpResponser.readTimeout = urlConnection.getReadTimeout();
+
+ return httpResponser;
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ if (urlConnection != null)
+ urlConnection.disconnect();
+ }
+ }
+
+ /**
+ * 默认的响应字符集
+ */
+ public String getDefaultContentEncoding() {
+ return this.defaultContentEncoding;
+ }
+
+ /**
+ * 设置默认的响应字符集
+ */
+ public void setDefaultContentEncoding(String defaultContentEncoding) {
+ this.defaultContentEncoding = defaultContentEncoding;
+ }
+
+ public int getDefaultTimeout() {
+ return defaultTimeout;
+ }
+
+ public void setDefaultTimeout(int defaultTimeout) {
+ this.defaultTimeout = defaultTimeout;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpResponse.java b/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpResponse.java
new file mode 100644
index 00000000..04cbe5e2
--- /dev/null
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/request/HttpResponse.java
@@ -0,0 +1,124 @@
+package org.elasticsearch.plugin.nlpcn.request;
+import java.util.Vector;
+
+
+/**
+ * 响应对象
+ */
+public class HttpResponse {
+
+ String urlString;
+
+ int defaultPort;
+
+ String file;
+
+ String host;
+
+ String path;
+
+ int port;
+
+ String protocol;
+
+ String query;
+
+ String ref;
+
+ String userInfo;
+
+ String contentEncoding;
+
+ String content;
+
+ String contentType;
+
+ int code;
+
+ String message;
+
+ String method;
+
+ int connectTimeout;
+
+ int readTimeout;
+
+ Vector contentCollection;
+
+ public String getContent() {
+ return content;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Vector getContentCollection() {
+ return contentCollection;
+ }
+
+ public String getContentEncoding() {
+ return contentEncoding;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public int getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public int getReadTimeout() {
+ return readTimeout;
+ }
+
+ public String getUrlString() {
+ return urlString;
+ }
+
+ public int getDefaultPort() {
+ return defaultPort;
+ }
+
+ public String getFile() {
+ return file;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ public String getUserInfo() {
+ return userInfo;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/nlpcn/es4sql/domain/Field.java b/src/main/java/org/nlpcn/es4sql/domain/Field.java
index 465f2f10..b2c96ff7 100644
--- a/src/main/java/org/nlpcn/es4sql/domain/Field.java
+++ b/src/main/java/org/nlpcn/es4sql/domain/Field.java
@@ -16,6 +16,33 @@ public class Field implements Cloneable{
private NestedType nested;
private ChildrenType children;
+ private Where where;
+ private String mode;
+ private String sortName;
+
+ public Where getWhere() {
+ return where;
+ }
+
+ public void setWhere(Where where) {
+ this.where = where;
+ }
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public String getSortName() {
+ return sortName;
+ }
+
+ public void setSortName(String sortName) {
+ this.sortName = sortName;
+ }
+
public Field(String name, String alias) {
this.name = name;
this.alias = alias;
diff --git a/src/main/java/org/nlpcn/es4sql/domain/Order.java b/src/main/java/org/nlpcn/es4sql/domain/Order.java
index de445ccf..27ccec6b 100644
--- a/src/main/java/org/nlpcn/es4sql/domain/Order.java
+++ b/src/main/java/org/nlpcn/es4sql/domain/Order.java
@@ -8,12 +8,26 @@
public class Order {
private String name;
private String type;
+ private boolean isNested = false;
+ private String mode;
+ private String path;
+ private Where condition;
public Order(String name, String type) {
this.name = name;
this.type = type;
}
+ public Order(boolean isNested, String mode, String path,
+ Where condition, String name, String type) {
+ this.isNested = isNested;
+ this.mode = mode;
+ this.path = path;
+ this.condition = condition;
+ this.name = name;
+ this.type = type;
+ }
+
public String getName() {
return name;
}
@@ -30,4 +44,35 @@ public void setType(String type) {
this.type = type;
}
+ public boolean isNested() {
+ return isNested;
+ }
+
+ public void setNested(boolean nested) {
+ isNested = nested;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public Where getCondition() {
+ return condition;
+ }
+
+ public void setCondition(Where condition) {
+ this.condition = condition;
+ }
}
diff --git a/src/main/java/org/nlpcn/es4sql/domain/Query.java b/src/main/java/org/nlpcn/es4sql/domain/Query.java
index 67708205..7a95bb61 100644
--- a/src/main/java/org/nlpcn/es4sql/domain/Query.java
+++ b/src/main/java/org/nlpcn/es4sql/domain/Query.java
@@ -57,4 +57,8 @@ public String[] getTypeArr() {
return list.toArray(new String[list.size()]);
}
+// public boolean replaceWhere(Where where){
+// this.where = where;
+// return true;
+// }
}
diff --git a/src/main/java/org/nlpcn/es4sql/domain/Select.java b/src/main/java/org/nlpcn/es4sql/domain/Select.java
index b4db1938..62f4db1b 100644
--- a/src/main/java/org/nlpcn/es4sql/domain/Select.java
+++ b/src/main/java/org/nlpcn/es4sql/domain/Select.java
@@ -3,7 +3,6 @@
import org.nlpcn.es4sql.domain.hints.Hint;
import org.nlpcn.es4sql.parse.SubQueryExpression;
-import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -79,6 +78,14 @@ public void addOrderBy(String name, String type) {
this.orderBys.add(new Order(name, type));
}
+ //TODO new add
+ public void addOrderBy(boolean isNested, String mode, String path,
+ Where condition, String name, String type) {
+ if ("_score".equals(name)) {
+ isQuery = true;
+ }
+ this.orderBys.add(new Order(isNested, mode, path, condition, name, type));
+ }
public void addField(Field field) {
if (field == null ) {
@@ -88,7 +95,7 @@ public void addField(Field field) {
this.selectAll = true;
}
- if(field instanceof MethodField && aggsFunctions.contains(field.getName().toUpperCase())) {
+ if(field instanceof MethodField && aggsFunctions.contains(field.getName().toUpperCase())) {
isAgg = true;
}
@@ -145,5 +152,10 @@ public boolean isOrderdSelect(){
public boolean isSelectAll() {
return selectAll;
}
+
+// public boolean replaceOrderBys(List orderBys){
+// this.orderBys = orderBys;
+// return true;
+// }
}
diff --git a/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java b/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java
index eb46060c..d56c6b6b 100644
--- a/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java
+++ b/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java
@@ -91,6 +91,11 @@ private static Field handleIdentifier(NestedType nestedType, String alias, Strin
Field field = handleIdentifier(new SQLIdentifierExpr(nestedType.field), alias, tableAlias);
field.setNested(nestedType);
field.setChildren(null);
+ if (nestedType.mode != null) {
+ field.setWhere(nestedType.where);
+ field.setMode(nestedType.mode);
+ field.setSortName(nestedType.field);
+ }
return field;
}
diff --git a/src/main/java/org/nlpcn/es4sql/parse/NestedType.java b/src/main/java/org/nlpcn/es4sql/parse/NestedType.java
index f1109c48..302f8e87 100644
--- a/src/main/java/org/nlpcn/es4sql/parse/NestedType.java
+++ b/src/main/java/org/nlpcn/es4sql/parse/NestedType.java
@@ -1,10 +1,7 @@
package org.nlpcn.es4sql.parse;
import com.alibaba.druid.sql.ast.SQLExpr;
-import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
-import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
-import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
-import com.alibaba.druid.sql.ast.expr.SQLTextLiteralExpr;
+import com.alibaba.druid.sql.ast.expr.*;
import org.nlpcn.es4sql.Util;
import org.nlpcn.es4sql.domain.Where;
import org.nlpcn.es4sql.exception.SqlParseException;
@@ -15,9 +12,12 @@
* Created by Eliran on 12/11/2015.
*/
public class NestedType {
+ //字段名称
public String field;
+ //排序时的路径和条件
public String path;
public Where where;
+ public String mode;
private boolean reverse;
private boolean simple;
@@ -30,7 +30,7 @@ public boolean tryFillFromExpr(SQLExpr expr) throws SqlParseException {
reverse = methodNameLower.equals("reverse_nested");
List parameters = method.getParameters();
- if (parameters.size() != 2 && parameters.size() != 1)
+ if (parameters.size() != 3 && parameters.size() != 2 && parameters.size() != 1)
throw new SqlParseException("on nested object only allowed 2 parameters (field,path)/(path,conditions..) or 1 parameter (field) ");
String field = Util.extendedToString(parameters.get(0));
@@ -52,25 +52,37 @@ public boolean tryFillFromExpr(SQLExpr expr) throws SqlParseException {
}
} else if (parameters.size() == 2) {
- SQLExpr secondParameter = parameters.get(1);
- if(secondParameter instanceof SQLTextLiteralExpr || secondParameter instanceof SQLIdentifierExpr || secondParameter instanceof SQLPropertyExpr) {
-
- String pathString = Util.extendedToString(secondParameter);
- if(pathString.equals(""))
+ SQLExpr lastParameter = parameters.get(1);
+ if (lastParameter instanceof SQLTextLiteralExpr || lastParameter instanceof SQLIdentifierExpr || lastParameter instanceof SQLPropertyExpr) {
+ String pathString = Util.extendedToString(lastParameter);
+ if (pathString.equals(""))
this.path = null;
else
this.path = pathString;
this.simple = true;
- }
- else {
+ } else {
this.path = field;
Where where = Where.newInstance();
- new SqlParser().parseWhere(secondParameter,where);
- if(where.getWheres().size() == 0)
+ new SqlParser().parseWhere(lastParameter, where);
+ if (where.getWheres().size() == 0)
throw new SqlParseException("unable to parse filter where.");
this.where = where;
simple = false;
}
+ } else if (parameters.size() == 3) {
+ this.path = field;
+ SQLExpr secondParameter = parameters.get(1);
+ if (secondParameter instanceof SQLAggregateExpr){
+ this.mode = ((SQLAggregateExpr) secondParameter).getMethodName();
+ this.field = ((SQLAggregateExpr) secondParameter).getArguments().get(0).toString();
+ }
+ SQLExpr lastParameter = parameters.get(2);
+ Where where = Where.newInstance();
+ new SqlParser().parseWhere(lastParameter, where);
+ if (where.getWheres().size() == 0)
+ throw new SqlParseException("unable to parse filter where.");
+ this.where = where;
+ simple = false;
}
return true;
diff --git a/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java b/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java
index 60df3739..67cb53f6 100644
--- a/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java
+++ b/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java
@@ -1,15 +1,13 @@
package org.nlpcn.es4sql.parse;
-import java.util.*;
-
+import com.alibaba.druid.sql.ast.SQLCommentHint;
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.SQLOrderBy;
+import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
-import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlSelectGroupByExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
-
-
-import org.nlpcn.es4sql.Util;
import org.nlpcn.es4sql.domain.*;
import org.nlpcn.es4sql.domain.Where.CONN;
import org.nlpcn.es4sql.domain.hints.Hint;
@@ -17,11 +15,16 @@
import org.nlpcn.es4sql.exception.SqlParseException;
import org.nlpcn.es4sql.spatial.SpatialParamsFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* es sql support
- *
+ *
* @author ansj
- *
+ *
*/
public class SqlParser {
@@ -51,7 +54,8 @@ private Select parseSelect(MySqlSelectQueryBlock query) throws SqlParseException
select.getHints().addAll(parseHints(query.getHints()));
findLimit(query.getLimit(), select);
-
+ //TODO 修改
+ //select.setOrderBys(findOrderBy(query.getOrderBy()));
findOrderBy(query, select);
findGroupBy(query, select);
@@ -150,7 +154,7 @@ private void explanCond(String opear, SQLExpr expr, Where where) throws SqlParse
if(Condition.OPEAR.methodNameToOpear.containsKey(methodName)){
Object[] methodParametersValue = getMethodValuesWithSubQueries(method);
- Condition condition = null;
+ Condition condition = null;
if(isNested)
condition = new Condition(CONN.valueOf(opear) ,soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName),methodParametersValue, nestedType);
@@ -197,7 +201,7 @@ else if(isChildren)
isChildren = true;
}
- Condition condition = null;
+ Condition condition = null;
if(isNested)
condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), nestedType);
@@ -217,19 +221,19 @@ else if(isChildren)
NestedType nestedType = new NestedType();
if(nestedType.tryFillFromExpr(between.getTestExpr())){
leftSide = nestedType.field;
-
+
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if(childrenType.tryFillFromExpr(between.getTestExpr())){
leftSide = childrenType.field;
-
+
isChildren = true;
}
- Condition condition = null;
-
+ Condition condition = null;
+
if(isNested)
condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, nestedType);
else if(isChildren)
@@ -247,21 +251,21 @@ else if (expr instanceof SQLMethodInvokeExpr) {
String methodName = methodExpr.getMethodName();
if(SpatialParamsFactory.isAllowedMethod(methodName)){
String fieldName = methodParameters.get(0).toString();
-
+
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(methodParameters.get(0))) {
fieldName = nestedType.field;
-
+
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(methodParameters.get(0))) {
fieldName = childrenType.field;
-
+
isChildren = true;
}
@@ -313,12 +317,12 @@ else if (methodName.toLowerCase().equals("script")){
}
} else if (expr instanceof SQLInSubQueryExpr){
SQLInSubQueryExpr sqlIn = (SQLInSubQueryExpr) expr;
-
+
Select innerSelect = parseSelect((MySqlSelectQueryBlock) sqlIn.getSubQuery().getQuery());
-
+
if(innerSelect.getFields() == null || innerSelect.getFields().size()!=1)
throw new SqlParseException("should only have one return field in subQuery");
-
+
SubQueryExpression subQueryExpression = new SubQueryExpression(innerSelect);
String leftSide = sqlIn.getExpr().toString();
@@ -329,18 +333,18 @@ else if (methodName.toLowerCase().equals("script")){
NestedType nestedType = new NestedType();
if(nestedType.tryFillFromExpr(sqlIn.getExpr())){
leftSide = nestedType.field;
-
+
isNested = true;
}
-
+
ChildrenType childrenType = new ChildrenType();
if(childrenType.tryFillFromExpr(sqlIn.getExpr())){
leftSide = childrenType.field;
-
+
isChildren = true;
}
- Condition condition = null;
+ Condition condition = null;
if(isNested)
condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, nestedType);
@@ -402,7 +406,7 @@ private Object parseValue(SQLExpr expr) throws SqlParseException {
}
- private void findSelect(MySqlSelectQueryBlock query, Select select,String tableAlias) throws SqlParseException {
+ private void findSelect(MySqlSelectQueryBlock query, Select select, String tableAlias) throws SqlParseException {
List selectList = query.getSelectList();
for (SQLSelectItem sqlSelectItem : selectList) {
Field field = FieldMaker.makeField(sqlSelectItem.getExpr(), sqlSelectItem.getAlias(),tableAlias);
@@ -486,6 +490,14 @@ private String sameAliasWhere(Where where, String... aliases) throws SqlParseExc
return firstAlias;
}
+ private List findOrderBy(SQLOrderBy orderBy){
+ List items = orderBy.getItems();
+ for (SQLSelectOrderByItem sqlSelectOrderByItem : items) {
+ SQLExpr expr = sqlSelectOrderByItem.getExpr();
+ }
+ return new ArrayList();
+ }
+
private void findOrderBy(MySqlSelectQueryBlock query, Select select) throws SqlParseException {
SQLOrderBy orderBy = query.getOrderBy();
@@ -501,8 +513,9 @@ private void findOrderBy(MySqlSelectQueryBlock query, Select select) throws SqlP
private void addOrderByToSelect(Select select, List items, String alias) throws SqlParseException {
for (SQLSelectOrderByItem sqlSelectOrderByItem : items) {
SQLExpr expr = sqlSelectOrderByItem.getExpr();
- String orderByName = FieldMaker.makeField(expr, null, null).toString();
-
+ Field field = FieldMaker.makeField(expr, null, null);
+ String orderByName = field.getName();
+ //String orderByName = FieldMaker.makeField(expr, null, null).toString();
if (sqlSelectOrderByItem.getType() == null) {
sqlSelectOrderByItem.setType(SQLOrderingSpecification.ASC);
}
@@ -510,8 +523,16 @@ private void addOrderByToSelect(Select select, List items,
orderByName = orderByName.replace("`", "");
if(alias!=null) orderByName = orderByName.replaceFirst(alias+"\\.","");
- select.addOrderBy(orderByName, type);
-
+ if (field.isNested()) {
+ String path = field.getNestedPath();
+ String mode = field.getMode();
+ String sortName = field.getSortName();
+ Where condition = field.getWhere();
+ select.addOrderBy(true, mode, path, condition, sortName, type);
+ } else {
+ select.addOrderBy(orderByName, type);
+ }
+ //select.addOrderBy(orderByName, type);
}
}
diff --git a/src/main/java/org/nlpcn/es4sql/query/DefaultQueryAction.java b/src/main/java/org/nlpcn/es4sql/query/DefaultQueryAction.java
index 19310d0c..3c96e9e0 100644
--- a/src/main/java/org/nlpcn/es4sql/query/DefaultQueryAction.java
+++ b/src/main/java/org/nlpcn/es4sql/query/DefaultQueryAction.java
@@ -10,12 +10,14 @@
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService;
+import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.nlpcn.es4sql.domain.*;
import org.nlpcn.es4sql.domain.hints.Hint;
import org.nlpcn.es4sql.domain.hints.HintType;
import org.nlpcn.es4sql.exception.SqlParseException;
import org.nlpcn.es4sql.query.maker.QueryMaker;
+import org.nlpcn.es4sql.query.maker.SortMaker;
/**
* Transform SQL query to standard Elasticsearch search query
@@ -149,8 +151,15 @@ private void setWhere(Where where) throws SqlParseException {
* list of Order object
*/
private void setSorts(List orderBys) {
+ //TODO 需要修改
for (Order order : orderBys) {
- request.addSort(order.getName(), SortOrder.valueOf(order.getType()));
+ boolean isNested = order.isNested();
+ if (isNested) {
+ SortBuilder sort = SortMaker.explan(order);
+ request.addSort(sort);
+ } else {
+ request.addSort(order.getName(), SortOrder.valueOf(order.getType()));
+ }
}
}
diff --git a/src/main/java/org/nlpcn/es4sql/query/ESActionFactory.java b/src/main/java/org/nlpcn/es4sql/query/ESActionFactory.java
index 95cda676..0e31c6b7 100644
--- a/src/main/java/org/nlpcn/es4sql/query/ESActionFactory.java
+++ b/src/main/java/org/nlpcn/es4sql/query/ESActionFactory.java
@@ -29,69 +29,66 @@
public class ESActionFactory {
- /**
- * Create the compatible Query object
- * based on the SQL query.
- *
- * @param sql The SQL query.
- * @return Query object.
- */
- public static QueryAction create(Client client, String sql) throws SqlParseException, SQLFeatureNotSupportedException {
- sql = sql.replaceAll("\n"," ");
+ /**
+ * Create the compatible Query object
+ * based on the SQL query.
+ *
+ * @param sql The SQL query.
+ * @return Query object.
+ */
+ public static QueryAction create(Client client, String sql) throws SqlParseException, SQLFeatureNotSupportedException {
+ sql = sql.replaceAll("\n", " ");
String firstWord = sql.substring(0, sql.indexOf(' '));
switch (firstWord.toUpperCase()) {
- case "SELECT":
- SQLQueryExpr sqlExpr = (SQLQueryExpr) toSqlExpr(sql);
- if(isJoin(sqlExpr,sql)){
+ case "SELECT":
+ SQLQueryExpr sqlExpr = (SQLQueryExpr) toSqlExpr(sql);
+ if (isJoin(sqlExpr, sql)) {
JoinSelect joinSelect = new SqlParser().parseJoinSelect(sqlExpr);
handleSubQueries(client, joinSelect.getFirstTable());
handleSubQueries(client, joinSelect.getSecondTable());
return ESJoinQueryActionFactory.createJoinAction(client, joinSelect);
- }
- else {
+ } else {
Select select = new SqlParser().parseSelect(sqlExpr);
handleSubQueries(client, select);
return handleSelect(client, select);
}
- case "DELETE":
- SQLStatementParser parser = createSqlStatementParser(sql);
- SQLDeleteStatement deleteStatement = parser.parseDeleteStatement();
- Delete delete = new SqlParser().parseDelete(deleteStatement);
- return new DeleteQueryAction(client, delete);
+// case "DELETE":
+// SQLStatementParser parser = createSqlStatementParser(sql);
+// SQLDeleteStatement deleteStatement = parser.parseDeleteStatement();
+// Delete delete = new SqlParser().parseDelete(deleteStatement);
+// return new DeleteQueryAction(client, delete);
case "SHOW":
- return new ShowQueryAction(client,sql);
- default:
- throw new SQLFeatureNotSupportedException(String.format("Unsupported query: %s", sql));
- }
- }
+ return new ShowQueryAction(client, sql);
+ default:
+ throw new SQLFeatureNotSupportedException(String.format("Unsupported query: %s", sql));
+ }
+ }
private static void handleSubQueries(Client client, Select select) throws SqlParseException {
- if (select.containsSubQueries())
- {
- for(SubQueryExpression subQueryExpression : select.getSubQueries()){
+ if (select.containsSubQueries()) {
+ for (SubQueryExpression subQueryExpression : select.getSubQueries()) {
QueryAction queryAction = handleSelect(client, subQueryExpression.getSelect());
- executeAndFillSubQuery(client , subQueryExpression,queryAction);
+ executeAndFillSubQuery(client, subQueryExpression, queryAction);
}
}
}
- private static void executeAndFillSubQuery(Client client , SubQueryExpression subQueryExpression,QueryAction queryAction) throws SqlParseException {
+ private static void executeAndFillSubQuery(Client client, SubQueryExpression subQueryExpression, QueryAction queryAction) throws SqlParseException {
List