Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 352d828

Browse files
committed
NLPchina#114 csv support on rest query - simple searches and join (no aggregations)
1 parent 3a66990 commit 352d828

19 files changed

+428
-122
lines changed

src/main/java/org/elasticsearch/plugin/nlpcn/ActionRequestRestExecuter.java

Lines changed: 0 additions & 68 deletions
This file was deleted.

src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package org.elasticsearch.plugin.nlpcn;
22

3-
import org.elasticsearch.action.ActionRequest;
43
import org.elasticsearch.client.Client;
54
import org.elasticsearch.common.inject.Inject;
65
import org.elasticsearch.common.settings.Settings;
6+
import org.elasticsearch.plugin.nlpcn.executors.ActionRequestRestExecuterFactory;
7+
import org.elasticsearch.plugin.nlpcn.executors.RestExecutor;
78
import org.elasticsearch.rest.*;
89
import org.nlpcn.es4sql.SearchDao;
10+
import org.nlpcn.es4sql.query.QueryAction;
911
import org.nlpcn.es4sql.query.SqlElasticRequestBuilder;
1012

13+
import java.util.Map;
14+
1115

1216
public class RestSqlAction extends BaseRestHandler {
1317

@@ -27,18 +31,18 @@ protected void handleRequest(RestRequest request, RestChannel channel, final Cli
2731
if (sql == null) {
2832
sql = request.content().toUtf8();
2933
}
30-
3134
SearchDao searchDao = new SearchDao(client);
32-
SqlElasticRequestBuilder actionRequestBuilder = searchDao.explain(sql);
33-
ActionRequest actionRequest = actionRequestBuilder.request();
35+
QueryAction queryAction= searchDao.explain(sql);
3436

3537
// TODO add unittests to explain. (rest level?)
3638
if (request.path().endsWith("/_explain")) {
37-
String jsonExplanation = actionRequestBuilder.explain();
39+
String jsonExplanation = queryAction.explain().explain();
3840
BytesRestResponse bytesRestResponse = new BytesRestResponse(RestStatus.OK, jsonExplanation);
3941
channel.sendResponse(bytesRestResponse);
4042
} else {
41-
new ActionRequestRestExecuter(actionRequestBuilder, channel, client).execute();
43+
Map<String, String> params = request.params();
44+
RestExecutor restExecutor = ActionRequestRestExecuterFactory.createExecutor(params.get("format"));
45+
restExecutor.execute(client,params,queryAction,channel);
4246
}
4347
}
4448
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
/**
4+
* Created by Eliran on 26/12/2015.
5+
*/
6+
public class ActionRequestRestExecuterFactory {
7+
public static RestExecutor createExecutor(String format) {
8+
if(format == null || format.equals("")){
9+
return new ElasticDefaultRestExecutor();
10+
}
11+
if(format.equalsIgnoreCase("csv")){
12+
return new CSVResultRestExecutor();
13+
}
14+
return null;
15+
}
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
import java.util.List;
4+
5+
/**
6+
* Created by Eliran on 27/12/2015.
7+
*/
8+
public class CSVResult {
9+
private final List<String> headers;
10+
private final List<String> lines;
11+
12+
public CSVResult(List<String> headers, List<String> lines) {
13+
this.headers = headers;
14+
this.lines = lines;
15+
}
16+
17+
public List<String> getHeaders() {
18+
return headers;
19+
}
20+
21+
public List<String> getLines() {
22+
return lines;
23+
}
24+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
import org.elasticsearch.client.Client;
4+
import org.elasticsearch.common.base.Joiner;
5+
import org.elasticsearch.plugin.nlpcn.QueryActionElasticExecutor;
6+
import org.elasticsearch.rest.BytesRestResponse;
7+
import org.elasticsearch.rest.RestChannel;
8+
import org.elasticsearch.rest.RestStatus;
9+
import org.nlpcn.es4sql.query.QueryAction;
10+
11+
import java.util.*;
12+
13+
/**
14+
* Created by Eliran on 26/12/2015.
15+
*/
16+
public class CSVResultRestExecutor implements RestExecutor {
17+
18+
@Override
19+
public void execute(Client client, Map<String, String> params, QueryAction queryAction, RestChannel channel) throws Exception {
20+
Object queryResult = QueryActionElasticExecutor.executeAnyAction(client, queryAction);
21+
boolean flat = false;
22+
if(params.containsKey("flat")){
23+
flat = Boolean.parseBoolean(params.get("flat"));
24+
}
25+
String separator = params.getOrDefault("separator",",");
26+
CSVResult result = CSVResultsExtractor.extractResults(queryResult,flat,separator);
27+
String newLine = params.getOrDefault("newLine","\n");
28+
String csvString = buildString(separator, result, newLine);
29+
BytesRestResponse bytesRestResponse = new BytesRestResponse(RestStatus.OK, csvString);
30+
channel.sendResponse(bytesRestResponse);
31+
}
32+
33+
private String buildString(String separator, CSVResult result, String newLine) {
34+
StringBuilder csv = new StringBuilder();
35+
csv.append(Joiner.on(separator).join(result.getHeaders()));
36+
csv.append(newLine);
37+
csv.append(Joiner.on(newLine).join(result.getLines()));
38+
return csv.toString();
39+
}
40+
41+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
import org.elasticsearch.search.SearchHit;
4+
import org.elasticsearch.search.SearchHits;
5+
6+
import java.util.*;
7+
8+
/**
9+
* Created by Eliran on 27/12/2015.
10+
*/
11+
public class CSVResultsExtractor {
12+
public static CSVResult extractResults(Object queryResult, boolean flat, String separator) {
13+
if(queryResult instanceof SearchHits){
14+
SearchHit[] hits = ((SearchHits) queryResult).getHits();
15+
Set<String> csvHeaders = new HashSet<>();
16+
List<Map<String,Object>> docsAsMap = new ArrayList<>();
17+
for(SearchHit hit : hits){
18+
Map<String, Object> doc = hit.sourceAsMap();
19+
mergeHeaders(csvHeaders,doc,flat);
20+
docsAsMap.add(doc);
21+
}
22+
List<String> headers = new ArrayList<>(csvHeaders);
23+
24+
List<String> csvLines = new ArrayList<>();
25+
for(Map<String,Object> doc : docsAsMap){
26+
String line = "";
27+
for(String header : headers){
28+
line += findFieldValue(header, doc, flat, separator);
29+
}
30+
csvLines.add(line.substring(0, line.length() - 1));
31+
}
32+
33+
return new CSVResult(headers,csvLines);
34+
}
35+
return null;
36+
}
37+
38+
private static String findFieldValue(String header, Map<String, Object> doc, boolean flat, String separator) {
39+
if(flat && header.contains(".")){
40+
String[] split = header.split("\\.");
41+
Object innerDoc = doc;
42+
for(String innerField : split){
43+
if(!(innerDoc instanceof Map)){
44+
return separator;
45+
}
46+
innerDoc = ((Map<String,Object>)innerDoc).get(innerField);
47+
if(innerDoc == null){
48+
return separator;
49+
}
50+
51+
}
52+
return innerDoc.toString() + separator;
53+
}
54+
else {
55+
if(doc.containsKey(header)){
56+
return doc.get(header).toString() + separator;
57+
}
58+
}
59+
return separator;
60+
}
61+
62+
private static void mergeHeaders(Set<String> headers, Map<String, Object> doc, boolean flat) {
63+
if (!flat) {
64+
headers.addAll(doc.keySet());
65+
return;
66+
}
67+
mergeFieldNamesRecursive(headers, doc, "");
68+
}
69+
70+
private static void mergeFieldNamesRecursive(Set<String> headers, Map<String, Object> doc, String prefix) {
71+
for(Map.Entry<String,Object> field : doc.entrySet()){
72+
Object value = field.getValue();
73+
if(value instanceof Map){
74+
mergeFieldNamesRecursive(headers,(Map<String,Object>) value,prefix+field.getKey()+".");
75+
}
76+
else {
77+
headers.add(prefix+field.getKey());
78+
}
79+
}
80+
}
81+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
import org.elasticsearch.action.ActionRequest;
4+
import org.elasticsearch.action.ActionRequestBuilder;
5+
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
6+
import org.elasticsearch.action.deletebyquery.DeleteByQueryRequest;
7+
import org.elasticsearch.action.search.SearchRequest;
8+
import org.elasticsearch.action.search.SearchResponse;
9+
import org.elasticsearch.client.Client;
10+
import org.elasticsearch.plugin.nlpcn.DeleteByQueryRestListener;
11+
import org.elasticsearch.plugin.nlpcn.ElasticJoinExecutor;
12+
import org.elasticsearch.plugin.nlpcn.GetIndexRequestRestListener;
13+
import org.elasticsearch.rest.RestChannel;
14+
import org.elasticsearch.rest.action.support.RestStatusToXContentListener;
15+
import org.nlpcn.es4sql.query.QueryAction;
16+
import org.nlpcn.es4sql.query.SqlElasticRequestBuilder;
17+
import org.nlpcn.es4sql.query.join.JoinRequestBuilder;
18+
19+
import java.util.Map;
20+
21+
22+
public class ElasticDefaultRestExecutor implements RestExecutor {
23+
24+
25+
public ElasticDefaultRestExecutor() {
26+
}
27+
28+
/**
29+
* Execute the ActionRequest and returns the REST response using the channel.
30+
*/
31+
@Override
32+
public void execute(Client client, Map<String, String> params, QueryAction queryAction, RestChannel channel) throws Exception{
33+
SqlElasticRequestBuilder requestBuilder = queryAction.explain();
34+
ActionRequest request = requestBuilder.request();
35+
request.listenerThreaded(false);
36+
37+
//todo: maby change to instanceof multi?
38+
if(requestBuilder instanceof JoinRequestBuilder){
39+
ElasticJoinExecutor executor = ElasticJoinExecutor.createJoinExecutor(client,requestBuilder);
40+
executor.run();
41+
executor.sendResponse(channel);
42+
}
43+
else if (request instanceof SearchRequest) {
44+
client.search((SearchRequest) request, new RestStatusToXContentListener<SearchResponse>(channel));
45+
} else if (request instanceof DeleteByQueryRequest) {
46+
ActionRequestBuilder elasticRequestBuilder = requestBuilder.getBuilder();
47+
elasticRequestBuilder.execute(new DeleteByQueryRestListener(channel));
48+
}
49+
else if(request instanceof GetIndexRequest) {
50+
requestBuilder.getBuilder().execute( new GetIndexRequestRestListener(channel, (GetIndexRequest) request));
51+
}
52+
53+
else {
54+
throw new Exception(String.format("Unsupported ActionRequest provided: %s", request.getClass().getName()));
55+
}
56+
}
57+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.elasticsearch.plugin.nlpcn.executors;
2+
3+
import org.elasticsearch.client.Client;
4+
import org.elasticsearch.rest.RestChannel;
5+
import org.nlpcn.es4sql.query.QueryAction;
6+
import org.nlpcn.es4sql.query.SqlElasticRequestBuilder;
7+
8+
import java.util.Map;
9+
10+
/**
11+
* Created by Eliran on 26/12/2015.
12+
*/
13+
public interface RestExecutor {
14+
public void execute(Client client, Map<String,String> params ,QueryAction queryAction, RestChannel channel) throws Exception;
15+
}

src/main/java/org/nlpcn/es4sql/SearchDao.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ public Client getClient() {
4242
* @return ES request
4343
* @throws SqlParseException
4444
*/
45-
public SqlElasticRequestBuilder explain(String sql) throws SqlParseException, SQLFeatureNotSupportedException {
46-
47-
QueryAction query = ESActionFactory.create(client, sql);
48-
return query.explain();
45+
public QueryAction explain(String sql) throws SqlParseException, SQLFeatureNotSupportedException {
46+
return ESActionFactory.create(client, sql);
4947
}
5048

49+
50+
5151
}

0 commit comments

Comments
 (0)