replace xcontent with datastructures for JSON building

This commit is contained in:
Jörg Prante 2021-10-20 16:39:12 +02:00
parent 9b38b62d42
commit a52894f663
11 changed files with 289 additions and 306 deletions

View file

@ -1,5 +1,4 @@
dependencies { dependencies {
api project(':cql-common') api project(':cql-common')
implementation "org.xbib:content-core:${project.property('xbib-content.version')}" implementation "org.xbib:datastructures-json-tiny:${project.property('xbib-datastructures.version')}"
implementation "org.xbib:content-json:${project.property('xbib-content.version')}"
} }

View file

@ -3,6 +3,6 @@ module org.xbib.cql.elasticsearch {
exports org.xbib.cql.elasticsearch.ast; exports org.xbib.cql.elasticsearch.ast;
exports org.xbib.cql.elasticsearch.model; exports org.xbib.cql.elasticsearch.model;
requires transitive org.xbib.cql; requires transitive org.xbib.cql;
requires org.xbib.content.core; requires org.xbib.datastructures.api;
requires org.xbib.content.json; requires org.xbib.datastructures.json.tiny;
} }

View file

@ -1,6 +1,5 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.cql.BooleanGroup; import org.xbib.cql.BooleanGroup;
import org.xbib.cql.BooleanOperator; import org.xbib.cql.BooleanOperator;
import org.xbib.cql.Comparitor; import org.xbib.cql.Comparitor;
@ -27,6 +26,7 @@ import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.cql.elasticsearch.ast.TokenType; import org.xbib.cql.elasticsearch.ast.TokenType;
import org.xbib.cql.elasticsearch.model.ElasticsearchQueryModel; import org.xbib.cql.elasticsearch.model.ElasticsearchQueryModel;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@ -45,7 +45,7 @@ public class ElasticsearchFilterGenerator implements Visitor {
private final String globalField; private final String globalField;
private FilterGenerator filterGen; private final FilterGenerator filterGen;
public ElasticsearchFilterGenerator(String globalField) { public ElasticsearchFilterGenerator(String globalField) {
this(globalField, new ElasticsearchQueryModel()); this(globalField, new ElasticsearchQueryModel());
@ -55,11 +55,7 @@ public class ElasticsearchFilterGenerator implements Visitor {
this.globalField = globalField; this.globalField = globalField;
this.model = model; this.model = model;
this.stack = new Stack<>(); this.stack = new Stack<>();
try { this.filterGen = new FilterGenerator();
this.filterGen = new FilterGenerator();
} catch (IOException e) {
// ignore
}
} }
public void addOrFilter(String filterKey, Collection<String> filterValues) { public void addOrFilter(String filterKey, Collection<String> filterValues) {
@ -76,7 +72,7 @@ public class ElasticsearchFilterGenerator implements Visitor {
} }
} }
public XContentBuilder getResult() throws IOException { public JsonBuilder getResult() {
return filterGen.getResult(); return filterGen.getResult();
} }

View file

@ -1,7 +1,5 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.content.core.DefaultXContentBuilder;
import org.xbib.cql.BooleanGroup; import org.xbib.cql.BooleanGroup;
import org.xbib.cql.BooleanOperator; import org.xbib.cql.BooleanOperator;
import org.xbib.cql.CQLParser; import org.xbib.cql.CQLParser;
@ -29,6 +27,7 @@ import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.cql.elasticsearch.ast.TokenType; import org.xbib.cql.elasticsearch.ast.TokenType;
import org.xbib.cql.elasticsearch.model.ElasticsearchQueryModel; import org.xbib.cql.elasticsearch.model.ElasticsearchQueryModel;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@ -67,7 +66,7 @@ public class ElasticsearchQueryGenerator implements Visitor {
private FacetsGenerator facetGen; private FacetsGenerator facetGen;
private XContentBuilder sort; private SortGenerator sortGen;
private final String globalField; private final String globalField;
@ -82,6 +81,7 @@ public class ElasticsearchQueryGenerator implements Visitor {
this.queryGen = new QueryGenerator(); this.queryGen = new QueryGenerator();
this.filterGen = new FilterGenerator(); this.filterGen = new FilterGenerator();
this.facetGen = new FacetsGenerator(); this.facetGen = new FacetsGenerator();
this.sortGen = new SortGenerator();
} }
public ElasticsearchQueryModel getModel() { public ElasticsearchQueryModel getModel() {
@ -98,11 +98,6 @@ public class ElasticsearchQueryGenerator implements Visitor {
return this; return this;
} }
public ElasticsearchQueryGenerator setSort(XContentBuilder sort) {
this.sort = sort;
return this;
}
public ElasticsearchQueryGenerator setBoostParams(String boostField, String modifier, Float factor, String boostMode) { public ElasticsearchQueryGenerator setBoostParams(String boostField, String modifier, Float factor, String boostMode) {
this.boostField = boostField; this.boostField = boostField;
this.modifier = modifier; this.modifier = modifier;
@ -137,16 +132,16 @@ public class ElasticsearchQueryGenerator implements Visitor {
return this; return this;
} }
public String getQueryResult() throws IOException { public String getQueryResult() {
return queryGen.getResult().string(); return queryGen.getResult().build();
} }
public String getFacetResult() throws IOException { public String getFacetResult() {
return facetGen.getResult().string(); return facetGen.getResult().build();
} }
public String getSourceResult() throws IOException { public String getSourceResult() {
return sourceGen.getResult().string(); return sourceGen.getResult().build();
} }
@Override @Override
@ -162,7 +157,7 @@ public class ElasticsearchQueryGenerator implements Visitor {
} }
if (model.hasFilter()) { if (model.hasFilter()) {
queryGen.startFiltered(); queryGen.startFiltered();
} else if (filterGenerator.getResult().string().length() > 0) { } else if (filterGenerator.getResult().build().length() > 0) {
queryGen.startFiltered(); queryGen.startFiltered();
} }
Node querynode = stack.pop(); Node querynode = stack.pop();
@ -180,11 +175,10 @@ public class ElasticsearchQueryGenerator implements Visitor {
filterGen.visit(model.getFilterExpression()); filterGen.visit(model.getFilterExpression());
filterGen.endFilter(); filterGen.endFilter();
queryGen.end(); queryGen.end();
} else if (filterGenerator.getResult().string().length() > 0) { } else if (filterGenerator.getResult().build().length() > 0) {
queryGen.end(); queryGen.end();
DefaultXContentBuilder contentBuilder = (DefaultXContentBuilder) filterGenerator.getResult(); JsonBuilder contentBuilder = filterGenerator.getResult();
byte[] b = contentBuilder.bytes().toBytes(); queryGen.getResult(). copy(contentBuilder);
queryGen.getResult().rawField("filter", b, 0, b.length);
queryGen.endFiltered(); queryGen.endFiltered();
} }
if (boostField != null) { if (boostField != null) {
@ -195,15 +189,13 @@ public class ElasticsearchQueryGenerator implements Visitor {
facetGen.visit(model.getFacetExpression()); facetGen.visit(model.getFacetExpression());
} }
queryGen.end(); queryGen.end();
Expression sortnode = model.getSort(); if (model.getSort() != null) {
SortGenerator sortGen = new SortGenerator(); sortGen = new SortGenerator();
if (sortnode != null) {
sortGen.start(); sortGen.start();
sortGen.visit(sortnode); sortGen.visit(model.getSort());
sortGen.end(); sortGen.end();
sort = sortGen.getResult();
} }
sourceGen.build(queryGen, from, size, sort, facetGen.getResult()); sourceGen.build(queryGen, from, size, sortGen.getResult(), facetGen.getResult());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException("unable to build a valid query from " + node + " , reason: " + e.getMessage(), e); throw new SyntaxException("unable to build a valid query from " + node + " , reason: " + e.getMessage(), e);
} }
@ -326,7 +318,7 @@ public class ElasticsearchQueryGenerator implements Visitor {
if (sb.length() > 0) { if (sb.length() > 0) {
sb.append('.'); sb.append('.');
} }
sb.append(modifier.toString()); sb.append(modifier);
modifier = stack.pop(); modifier = stack.pop();
} }
String modifiable = sb.toString(); String modifiable = sb.toString();

View file

@ -1,13 +1,12 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.content.json.JsonXContent;
import org.xbib.cql.SyntaxException; import org.xbib.cql.SyntaxException;
import org.xbib.cql.elasticsearch.ast.Expression; import org.xbib.cql.elasticsearch.ast.Expression;
import org.xbib.cql.elasticsearch.ast.Modifier; import org.xbib.cql.elasticsearch.ast.Modifier;
import org.xbib.cql.elasticsearch.ast.Name; import org.xbib.cql.elasticsearch.ast.Name;
import org.xbib.cql.elasticsearch.ast.Operator; import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -20,36 +19,36 @@ public class FacetsGenerator implements Visitor {
private int facetlength = 10; private int facetlength = 10;
private final XContentBuilder builder; private final JsonBuilder builder;
public FacetsGenerator() throws IOException { public FacetsGenerator() throws IOException {
this.builder = JsonXContent.contentBuilder(); this.builder = new JsonBuilder();
} }
public void start() throws IOException { public void start() throws IOException {
builder.startObject(); builder.beginMap();
} }
public void end() throws IOException { public void end() throws IOException {
builder.endObject(); builder.endMap();
} }
public void startFacets() throws IOException { public void startFacets() throws IOException {
builder.startObject("aggregations"); builder.beginMap("aggregations");
} }
public void endFacets() throws IOException { public void endFacets() throws IOException {
builder.endObject(); builder.endMap();
} }
public XContentBuilder getResult() throws IOException { public JsonBuilder getResult() {
return builder; return builder;
} }
@Override @Override
public void visit(Token node) { public void visit(Token node) {
try { try {
builder.value(node.toString().getBytes()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -58,7 +57,7 @@ public class FacetsGenerator implements Visitor {
@Override @Override
public void visit(Name node) { public void visit(Name node) {
try { try {
builder.value(node.toString().getBytes()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -67,7 +66,7 @@ public class FacetsGenerator implements Visitor {
@Override @Override
public void visit(Modifier node) { public void visit(Modifier node) {
try { try {
builder.value(node.toString().getBytes()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -76,7 +75,7 @@ public class FacetsGenerator implements Visitor {
@Override @Override
public void visit(Operator node) { public void visit(Operator node) {
try { try {
builder.value(node.toString().getBytes()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -88,8 +87,9 @@ public class FacetsGenerator implements Visitor {
Operator op = node.getOperator(); Operator op = node.getOperator();
switch (op) { switch (op) {
case TERMS_FACET: { case TERMS_FACET: {
builder.startObject().field("myfacet", "myvalue") builder.beginMap()
.endObject(); .field("myfacet", "myvalue")
.endMap();
break; break;
} }
default: default:
@ -122,7 +122,7 @@ public class FacetsGenerator implements Visitor {
break; break;
} }
} }
builder.startObject(); builder.beginMap();
for (String index : facetMap.keySet()) { for (String index : facetMap.keySet()) {
if ("*".equals(index)) { if ("*".equals(index)) {
continue; continue;
@ -130,18 +130,19 @@ public class FacetsGenerator implements Visitor {
// TODO(jprante) range aggregations etc. // TODO(jprante) range aggregations etc.
String facetType = "terms"; String facetType = "terms";
Integer size = facetMap.get(index); Integer size = facetMap.get(index);
builder.field(index) builder.buildKey(index)
.startObject() .beginMap()
.field(facetType).startObject() .buildKey(facetType)
.beginMap()
.field("field", index) .field("field", index)
.field("size", size > 0 ? size : 10) .field("size", size > 0 ? size : 10)
.startObject("order") .beginMap("order")
.field(order, dir) .field(order, dir)
.endObject() .endMap()
.endObject(); .endMap();
builder.endObject(); builder.endMap();
} }
builder.endObject(); builder.endMap();
return this; return this;
} }

View file

@ -1,7 +1,5 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.content.json.JsonXContent;
import org.xbib.cql.SyntaxException; import org.xbib.cql.SyntaxException;
import org.xbib.cql.elasticsearch.ast.Expression; import org.xbib.cql.elasticsearch.ast.Expression;
import org.xbib.cql.elasticsearch.ast.Modifier; import org.xbib.cql.elasticsearch.ast.Modifier;
@ -10,6 +8,7 @@ import org.xbib.cql.elasticsearch.ast.Node;
import org.xbib.cql.elasticsearch.ast.Operator; import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.cql.util.QuotedStringTokenizer; import org.xbib.cql.util.QuotedStringTokenizer;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
@ -18,10 +17,10 @@ import java.io.IOException;
*/ */
public class FilterGenerator implements Visitor { public class FilterGenerator implements Visitor {
private XContentBuilder builder; private final JsonBuilder builder;
public FilterGenerator() throws IOException { public FilterGenerator() {
this.builder = JsonXContent.contentBuilder(); this.builder = new JsonBuilder();
} }
public FilterGenerator(QueryGenerator queryGenerator) throws IOException { public FilterGenerator(QueryGenerator queryGenerator) throws IOException {
@ -29,33 +28,33 @@ public class FilterGenerator implements Visitor {
} }
public FilterGenerator start() throws IOException { public FilterGenerator start() throws IOException {
builder.startObject(); builder.beginMap();
return this; return this;
} }
public FilterGenerator end() throws IOException { public FilterGenerator end() throws IOException {
builder.endObject(); builder.endMap();
return this; return this;
} }
public FilterGenerator startFilter() throws IOException { public FilterGenerator startFilter() throws IOException {
builder.startObject("filter"); builder.beginMap("filter");
return this; return this;
} }
public FilterGenerator endFilter() throws IOException { public FilterGenerator endFilter() throws IOException {
builder.endObject(); builder.endMap();
return this; return this;
} }
public XContentBuilder getResult() throws IOException { public JsonBuilder getResult() {
return builder; return builder;
} }
@Override @Override
public void visit(Token node) { public void visit(Token node) {
try { try {
builder.value(node.getString()); builder.buildValue(node.getString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -64,7 +63,7 @@ public class FilterGenerator implements Visitor {
@Override @Override
public void visit(Name node) { public void visit(Name node) {
try { try {
builder.field(node.toString()); builder.buildKey(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -73,7 +72,7 @@ public class FilterGenerator implements Visitor {
@Override @Override
public void visit(Modifier node) { public void visit(Modifier node) {
try { try {
builder.value(node.toString()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -82,7 +81,7 @@ public class FilterGenerator implements Visitor {
@Override @Override
public void visit(Operator node) { public void visit(Operator node) {
try { try {
builder.value(node.toString()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -111,17 +110,18 @@ public class FilterGenerator implements Visitor {
case EQUALS: { case EQUALS: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; String value = tok2 != null ? tok2.getString() : "";
builder.startObject(tok2 != null && tok2.isBoundary() ? "prefix" : "term"); builder.beginMap(tok2 != null && tok2.isBoundary() ? "prefix" : "term");
builder.field(field, value).endObject(); builder.field(field, value)
.endMap();
break; break;
} }
case NOT_EQUALS: { case NOT_EQUALS: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; String value = tok2 != null ? tok2.getString() : "";
builder.startObject("not") builder.beginMap("not")
.startObject(tok2 != null && tok2.isBoundary() ? "prefix" : "term") .beginMap(tok2 != null && tok2.isBoundary() ? "prefix" : "term")
.field(field, value) .field(field, value)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case ALL: { case ALL: {
@ -129,18 +129,18 @@ public class FilterGenerator implements Visitor {
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
boolean phrase = arg2 instanceof Token && ((Token) arg2).isQuoted(); boolean phrase = arg2 instanceof Token && ((Token) arg2).isQuoted();
if (phrase) { if (phrase) {
builder.startArray("and"); builder.beginCollection("and");
QuotedStringTokenizer qst = new QuotedStringTokenizer(value); QuotedStringTokenizer qst = new QuotedStringTokenizer(value);
while (qst.hasMoreTokens()) { while (qst.hasMoreTokens()) {
builder.startObject().startObject("term") builder.beginMap().beginMap("term")
.field(field, qst.nextToken()) .field(field, qst.nextToken())
.endObject().endObject(); .endMap().endMap();
} }
builder.endArray(); builder.endCollection();
} else { } else {
builder.startObject(tok2 != null && tok2.isBoundary() ? "prefix" : "term") builder.beginMap(tok2 != null && tok2.isBoundary() ? "prefix" : "term")
.field(field, value) .field(field, value)
.endObject(); .endMap();
} }
break; break;
} }
@ -149,66 +149,66 @@ public class FilterGenerator implements Visitor {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
if (phrase) { if (phrase) {
builder.startArray("or"); builder.beginCollection("or");
QuotedStringTokenizer qst = new QuotedStringTokenizer(value); QuotedStringTokenizer qst = new QuotedStringTokenizer(value);
while (qst.hasMoreTokens()) { while (qst.hasMoreTokens()) {
builder.startObject().startObject("term") builder.beginMap().beginMap("term")
.field(field, qst.nextToken()).endObject().endObject(); .field(field, qst.nextToken()).endMap().endMap();
} }
builder.endArray(); builder.endCollection();
} else { } else {
builder.startObject(tok2 != null && tok2.isBoundary() ? "prefix" : "term") builder.beginMap(tok2 != null && tok2.isBoundary() ? "prefix" : "term")
.field(field, value) .field(field, value)
.endObject(); .endMap();
} }
break; break;
} }
case RANGE_GREATER_THAN: { case RANGE_GREATER_THAN: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; String value = tok2 != null ? tok2.getString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("from", value) .field("from", value)
.field("include_lower", false) .field("include_lower", false)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_GREATER_OR_EQUAL: { case RANGE_GREATER_OR_EQUAL: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("from", value) .field("from", value)
.field("include_lower", true) .field("include_lower", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_LESS_THAN: { case RANGE_LESS_THAN: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("to", value) .field("to", value)
.field("include_upper", false) .field("include_upper", false)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_LESS_OR_EQUALS: { case RANGE_LESS_OR_EQUALS: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("to", value) .field("to", value)
.field("include_upper", true) .field("include_upper", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_WITHIN: { case RANGE_WITHIN: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; String value = tok2 != null ? tok2.getString() : "";
String[] s = value.split(" "); String[] s = value.split(" ");
builder.startObject("range").startObject(field). builder.beginMap("range").beginMap(field).
field("from", s[0]) field("from", s[0])
.field("to", s[1]) .field("to", s[1])
.field("include_lower", true) .field("include_lower", true)
.field("include_upper", true) .field("include_upper", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case AND: { case AND: {
@ -217,18 +217,18 @@ public class FilterGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
builder.startArray("must"); builder.beginCollection("must");
Node[] args = node.getArgs(); Node[] args = node.getArgs();
for (int i = 0; i < node.getArgs().length; i++) { for (int i = 0; i < node.getArgs().length; i++) {
if (args[i].isVisible()) { if (args[i].isVisible()) {
builder.startObject(); builder.beginMap();
args[i].accept(this); args[i].accept(this);
builder.endObject(); builder.endMap();
} }
} }
builder.endArray(); builder.endCollection();
builder.endObject(); builder.endMap();
} }
break; break;
} }
@ -238,51 +238,51 @@ public class FilterGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
builder.startArray("should"); builder.beginCollection("should");
Node[] args = node.getArgs(); Node[] args = node.getArgs();
for (int i = 0; i < node.getArgs().length; i++) { for (int i = 0; i < node.getArgs().length; i++) {
if (args[i].isVisible()) { if (args[i].isVisible()) {
builder.startObject(); builder.beginMap();
args[i].accept(this); args[i].accept(this);
builder.endObject(); builder.endMap();
} }
} }
builder.endArray(); builder.endCollection();
builder.endObject(); builder.endMap();
} }
break; break;
} }
case OR_FILTER: { case OR_FILTER: {
builder.startObject("bool"); builder.beginMap("bool");
builder.startArray("should"); builder.beginCollection("should");
Node[] args = node.getArgs(); Node[] args = node.getArgs();
for (int i = 0; i < args.length; i += 2) { for (int i = 0; i < args.length; i += 2) {
if (args[i].isVisible()) { if (args[i].isVisible()) {
builder.startObject().startObject("term"); builder.beginMap().beginMap("term");
args[i].accept(this); args[i].accept(this);
args[i + 1].accept(this); args[i + 1].accept(this);
builder.endObject().endObject(); builder.endMap().endMap();
} }
} }
builder.endArray(); builder.endCollection();
builder.endObject(); builder.endMap();
break; break;
} }
case AND_FILTER: { case AND_FILTER: {
builder.startObject("bool"); builder.beginMap("bool");
builder.startArray("must"); builder.beginCollection("must");
Node[] args = node.getArgs(); Node[] args = node.getArgs();
for (int i = 0; i < args.length; i += 2) { for (int i = 0; i < args.length; i += 2) {
if (args[i].isVisible()) { if (args[i].isVisible()) {
builder.startObject().startObject("term"); builder.beginMap().beginMap("term");
args[i].accept(this); args[i].accept(this);
args[i + 1].accept(this); args[i + 1].accept(this);
builder.endObject().endObject(); builder.endMap().endMap();
} }
} }
builder.endArray(); builder.endCollection();
builder.endObject(); builder.endMap();
break; break;
} }
case ANDNOT: { case ANDNOT: {
@ -291,18 +291,18 @@ public class FilterGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
builder.startArray("must_not"); builder.beginCollection("must_not");
Node[] args = node.getArgs(); Node[] args = node.getArgs();
for (int i = 0; i < node.getArgs().length; i++) { for (int i = 0; i < node.getArgs().length; i++) {
if (args[i].isVisible()) { if (args[i].isVisible()) {
builder.startObject(); builder.beginMap();
args[i].accept(this); args[i].accept(this);
builder.endObject(); builder.endMap();
} }
} }
builder.endArray(); builder.endCollection();
builder.endObject(); builder.endMap();
} }
break; break;
} }
@ -310,19 +310,19 @@ public class FilterGenerator implements Visitor {
String field = arg1.toString(); String field = arg1.toString();
// we assume a default of 10 words is enough for proximity // we assume a default of 10 words is enough for proximity
String value = arg2 != null ? arg2.toString() + "~10" : ""; String value = arg2 != null ? arg2.toString() + "~10" : "";
builder.startObject("field").field(field, value).endObject(); builder.beginMap("field").field(field, value).endMap();
break; break;
} }
case TERM_FILTER: { case TERM_FILTER: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("term").field(field, value).endObject(); builder.beginMap("term").field(field, value).endMap();
break; break;
} }
case QUERY_FILTER: { case QUERY_FILTER: {
builder.startObject("query"); builder.beginMap("query");
arg1.accept(this); arg1.accept(this);
builder.endObject(); builder.endMap();
break; break;
} }
default: default:

View file

@ -1,7 +1,5 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.content.json.JsonXContent;
import org.xbib.cql.SyntaxException; import org.xbib.cql.SyntaxException;
import org.xbib.cql.elasticsearch.ast.Expression; import org.xbib.cql.elasticsearch.ast.Expression;
import org.xbib.cql.elasticsearch.ast.Modifier; import org.xbib.cql.elasticsearch.ast.Modifier;
@ -9,53 +7,54 @@ import org.xbib.cql.elasticsearch.ast.Name;
import org.xbib.cql.elasticsearch.ast.Node; import org.xbib.cql.elasticsearch.ast.Node;
import org.xbib.cql.elasticsearch.ast.Operator; import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
/** /**
* Build Elasticsearch query from abstract syntax tree. * Build Elasticsearch query from abstract syntax tree.
*/ */
public class QueryGenerator implements Visitor { public class QueryGenerator implements Visitor {
private final XContentBuilder builder; private final JsonBuilder builder;
public QueryGenerator() throws IOException { public QueryGenerator() {
this.builder = JsonXContent.contentBuilder(); this.builder = new JsonBuilder();
} }
public void start() throws IOException { public void start() throws IOException {
builder.startObject(); builder.beginMap();
} }
public void end() throws IOException { public void end() throws IOException {
builder.endObject(); builder.endMap();
} }
public void startFiltered() throws IOException { public void startFiltered() throws IOException {
builder.startObject("filtered").startObject("query"); builder.beginMap("filtered").beginMap("query");
} }
public void endFiltered() throws IOException { public void endFiltered() throws IOException {
builder.endObject(); builder.endMap();
} }
public void startBoost(String boostField, String modifier, Float factor, String boostMode) throws IOException { public void startBoost(String boostField, String modifier, Float factor, String boostMode) throws IOException {
builder.startObject("function_score") builder.beginMap("function_score")
.startObject("field_value_factor") .beginMap("field_value_factor")
.field("field", boostField) .field("field", boostField)
.field("modifier", modifier != null ? modifier : "log1p") .field("modifier", modifier != null ? modifier : "log1p")
.field("factor", factor != null ? factor : 1.0f) .field("factor", factor != null ? factor : 1.0f)
.endObject() .endMap()
.field("boost_mode", boostMode != null ? boostMode : "multiply") .field("boost_mode", boostMode != null ? boostMode : "multiply")
.startObject("query"); .beginMap("query");
} }
public void endBoost() throws IOException { public void endBoost() throws IOException {
builder.endObject().endObject(); builder.endMap().endMap();
} }
public XContentBuilder getResult() { public JsonBuilder getResult() {
return builder; return builder;
} }
@ -64,19 +63,19 @@ public class QueryGenerator implements Visitor {
try { try {
switch (token.getType()) { switch (token.getType()) {
case BOOL: case BOOL:
builder.value(token.getBoolean()); builder.buildValue(token.getBoolean());
break; break;
case INT: case INT:
builder.value(token.getInteger()); builder.buildValue(token.getInteger());
break; break;
case FLOAT: case FLOAT:
builder.value(token.getFloat()); builder.buildValue(token.getFloat());
break; break;
case DATETIME: case DATETIME:
builder.value(token.getDate()); builder.buildValue(token.getDate());
break; break;
case STRING: case STRING:
builder.value(token.getString()); builder.buildValue(token.getString());
break; break;
default: default:
throw new IOException("unknown token type: " + token); throw new IOException("unknown token type: " + token);
@ -89,7 +88,7 @@ public class QueryGenerator implements Visitor {
@Override @Override
public void visit(Name node) { public void visit(Name node) {
try { try {
builder.field(node.toString()); builder.buildKey(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -98,7 +97,7 @@ public class QueryGenerator implements Visitor {
@Override @Override
public void visit(Modifier node) { public void visit(Modifier node) {
try { try {
builder.value(node.toString()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -107,7 +106,7 @@ public class QueryGenerator implements Visitor {
@Override @Override
public void visit(Operator node) { public void visit(Operator node) {
try { try {
builder.value(node.toString()); builder.buildValue(node.toString());
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);
} }
@ -123,7 +122,7 @@ public class QueryGenerator implements Visitor {
switch (op.getArity()) { switch (op.getArity()) {
case 0: { case 0: {
if (op == Operator.MATCH_ALL) { if (op == Operator.MATCH_ALL) {
builder.startObject("match_all").endObject(); builder.beginMap("match_all").endMap();
} }
break; break;
} }
@ -148,91 +147,91 @@ public class QueryGenerator implements Visitor {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; // with quote String value = arg2 != null ? arg2.toString() : ""; // with quote
// with phrase boost // with phrase boost
builder.startObject("bool") builder.beginMap("bool")
.startArray("should") .beginCollection("should")
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", value) .field("query", value)
.field("fields", new String[]{field}) .field("fields", Collections.singletonList(field))
.field("analyze_wildcard", true) .field("analyze_wildcard", true)
.field("default_operator", "and") .field("default_operator", "and")
.endObject() .endMap()
.endObject() .endMap()
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", "\"" + value + "\"") .field("query", "\"" + value + "\"")
.field("fields", new String[]{ field + "^2"}) .field("fields", Collections.singletonList(field + "^2"))
.field("default_operator", "and") .field("default_operator", "and")
.endObject() .endMap()
.endObject() .endMap()
.endArray() .endCollection()
.field("minimum_should_match", "1") .field("minimum_should_match", "1")
.endObject(); .endMap();
break; break;
} }
case NOT_EQUALS: { case NOT_EQUALS: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; // with quote String value = arg2 != null ? arg2.toString() : ""; // with quote
builder.startObject("bool") builder.beginMap("bool")
.startObject("must_not") .beginMap("must_not")
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", value) .field("query", value)
.field("fields", new String[]{field}) .field("fields", Collections.singletonList(field))
.field("analyze_wildcard", true) .field("analyze_wildcard", true)
.field("default_operator", "and") .field("default_operator", "and")
.endObject() .endMap()
.endObject() .endMap()
.endObject(); .endMap();
break; break;
} }
case ALL: { case ALL: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; // always unquoted String value = tok2 != null ? tok2.getString() : ""; // always unquoted
// with phrase boost // with phrase boost
builder.startObject("bool") builder.beginMap("bool")
.startArray("should") .beginCollection("should")
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", value) .field("query", value)
.field("fields", new String[]{field}) .field("fields", Collections.singletonList(field))
.field("analyze_wildcard", true) .field("analyze_wildcard", true)
.field("default_operator", "and") .field("default_operator", "and")
.endObject() .endMap()
.endObject() .endMap()
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", "\"" + value + "\"") .field("query", "\"" + value + "\"")
.field("fields", new String[]{ field + "^2"}) .field("fields", Collections.singletonList(field + "^2"))
.field("default_operator", "and") .field("default_operator", "and")
.endObject() .endMap()
.endObject() .endMap()
.endArray() .endCollection()
.field("minimum_should_match", "1") .field("minimum_should_match", "1")
.endObject(); .endMap();
break; break;
} }
case ANY: { case ANY: {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2 != null ? tok2.getString() : ""; // always unquoted String value = tok2 != null ? tok2.getString() : ""; // always unquoted
// with phrase boost // with phrase boost
builder.startObject("bool") builder.beginMap("bool")
.startArray("should") .beginCollection("should")
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", value) .field("query", value)
.field("fields", new String[]{field}) .field("fields", Collections.singletonList(field))
.field("analyze_wildcard", true) .field("analyze_wildcard", true)
.endObject() .endMap()
.endObject() .endMap()
.startObject() .beginMap()
.startObject("simple_query_string") .beginMap("simple_query_string")
.field("query", "\"" + value + "\"") .field("query", "\"" + value + "\"")
.field("fields", new String[]{ field + "^2"}) .field("fields", Collections.singletonList(field + "^2"))
.endObject() .endMap()
.endObject() .endMap()
.endArray() .endCollection()
.field("minimum_should_match", "1") .field("minimum_should_match", "1")
.endObject(); .endMap();
break; break;
} }
case PHRASE: { case PHRASE: {
@ -240,18 +239,18 @@ public class QueryGenerator implements Visitor {
String field = arg1.toString(); String field = arg1.toString();
String value = tok2.isQuoted() ? tok2.getString() : arg2.toString(); String value = tok2.isQuoted() ? tok2.getString() : arg2.toString();
if (tok2.isAll()) { if (tok2.isAll()) {
builder.startObject("match_all").endObject(); builder.beginMap("match_all").endMap();
} else if (tok2.isWildcard()) { } else if (tok2.isWildcard()) {
builder.startObject("wildcard").field(field, value).endObject(); builder.beginMap("wildcard").field(field, value).endMap();
} else if (tok2.isBoundary()) { } else if (tok2.isBoundary()) {
builder.startObject("prefix").field(field, value).endObject(); builder.beginMap("prefix").field(field, value).endMap();
} else { } else {
builder.startObject("simple_query_string") builder.beginMap("simple_query_string")
.field("query", value) .field("query", value)
.field("fields", new String[]{field}) .field("fields",Collections.singletonList(field))
.field("analyze_wildcard", true) .field("analyze_wildcard", true)
.field("default_operator", "and") .field("default_operator", "and")
.endObject(); .endMap();
} }
} }
break; break;
@ -259,37 +258,37 @@ public class QueryGenerator implements Visitor {
case RANGE_GREATER_THAN: { case RANGE_GREATER_THAN: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("from", value) .field("from", value)
.field("include_lower", false) .field("include_lower", false)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_GREATER_OR_EQUAL: { case RANGE_GREATER_OR_EQUAL: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("from", value) .field("from", value)
.field("include_lower", true) .field("include_lower", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_LESS_THAN: { case RANGE_LESS_THAN: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("to", value) .field("to", value)
.field("include_upper", false) .field("include_upper", false)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_LESS_OR_EQUALS: { case RANGE_LESS_OR_EQUALS: {
String field = arg1.toString(); String field = arg1.toString();
String value = arg2 != null ? arg2.toString() : ""; String value = arg2 != null ? arg2.toString() : "";
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("to", value) .field("to", value)
.field("include_upper", true) .field("include_upper", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case RANGE_WITHIN: { case RANGE_WITHIN: {
@ -310,12 +309,12 @@ public class QueryGenerator implements Visitor {
from = tok2.getStringList().get(0); from = tok2.getStringList().get(0);
to = tok2.getStringList().get(1); to = tok2.getStringList().get(1);
} }
builder.startObject("range").startObject(field) builder.beginMap("range").beginMap(field)
.field("from", from) .field("from", from)
.field("to", to) .field("to", to)
.field("include_lower", true) .field("include_lower", true)
.field("include_upper", true) .field("include_upper", true)
.endObject().endObject(); .endMap().endMap();
break; break;
} }
case AND: { case AND: {
@ -324,23 +323,23 @@ public class QueryGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
if (arg1.isVisible() && arg2.isVisible()) { if (arg1.isVisible() && arg2.isVisible()) {
builder.startArray("must").startObject(); builder.beginCollection("must").beginMap();
arg1.accept(this); arg1.accept(this);
builder.endObject().startObject(); builder.endMap().beginMap();
arg2.accept(this); arg2.accept(this);
builder.endObject().endArray(); builder.endMap().endCollection();
} else if (arg1.isVisible()) { } else if (arg1.isVisible()) {
builder.startObject("must"); builder.beginMap("must");
arg1.accept(this); arg1.accept(this);
builder.endObject(); builder.endMap();
} else if (arg2.isVisible()) { } else if (arg2.isVisible()) {
builder.startObject("must"); builder.beginMap("must");
arg2.accept(this); arg2.accept(this);
builder.endObject(); builder.endMap();
} }
builder.endObject(); builder.endMap();
} }
break; break;
} }
@ -351,23 +350,23 @@ public class QueryGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
if (arg1.isVisible() && arg2.isVisible()) { if (arg1.isVisible() && arg2.isVisible()) {
builder.startArray("should").startObject(); builder.beginCollection("should").beginMap();
arg1.accept(this); arg1.accept(this);
builder.endObject().startObject(); builder.endMap().beginMap();
arg2.accept(this); arg2.accept(this);
builder.endObject().endArray(); builder.endMap().endCollection();
} else if (arg1.isVisible()) { } else if (arg1.isVisible()) {
builder.startObject("should"); builder.beginMap("should");
arg1.accept(this); arg1.accept(this);
builder.endObject(); builder.endMap();
} else if (arg2.isVisible()) { } else if (arg2.isVisible()) {
builder.startObject("should"); builder.beginMap("should");
arg2.accept(this); arg2.accept(this);
builder.endObject(); builder.endMap();
} }
builder.endObject(); builder.endMap();
} }
break; break;
} }
@ -377,23 +376,23 @@ public class QueryGenerator implements Visitor {
arg1.accept(this); arg1.accept(this);
} }
} else { } else {
builder.startObject("bool"); builder.beginMap("bool");
if (arg1.isVisible() && arg2.isVisible()) { if (arg1.isVisible() && arg2.isVisible()) {
builder.startArray("must_not").startObject(); builder.beginCollection("must_not").beginMap();
arg1.accept(this); arg1.accept(this);
builder.endObject().startObject(); builder.endMap().beginMap();
arg2.accept(this); arg2.accept(this);
builder.endObject().endArray(); builder.endMap().endCollection();
} else if (arg1.isVisible()) { } else if (arg1.isVisible()) {
builder.startObject("must_not"); builder.beginMap("must_not");
arg1.accept(this); arg1.accept(this);
builder.endObject(); builder.endMap();
} else if (arg2.isVisible()) { } else if (arg2.isVisible()) {
builder.startObject("must_not"); builder.beginMap("must_not");
arg2.accept(this); arg2.accept(this);
builder.endObject(); builder.endMap();
} }
builder.endObject(); builder.endMap();
} }
break; break;
} }
@ -401,7 +400,7 @@ public class QueryGenerator implements Visitor {
String field = arg1.toString(); String field = arg1.toString();
// we assume a default of 10 words is enough for proximity // we assume a default of 10 words is enough for proximity
String value = arg2 != null ? arg2 + "~10" : ""; String value = arg2 != null ? arg2 + "~10" : "";
builder.startObject("field").field(field, value).endObject(); builder.beginMap("field").field(field, value).endMap();
break; break;
} }
default: default:

View file

@ -1,7 +1,5 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.content.json.JsonXContent;
import org.xbib.cql.SyntaxException; import org.xbib.cql.SyntaxException;
import org.xbib.cql.elasticsearch.ast.Expression; import org.xbib.cql.elasticsearch.ast.Expression;
import org.xbib.cql.elasticsearch.ast.Modifier; import org.xbib.cql.elasticsearch.ast.Modifier;
@ -9,6 +7,7 @@ import org.xbib.cql.elasticsearch.ast.Name;
import org.xbib.cql.elasticsearch.ast.Node; import org.xbib.cql.elasticsearch.ast.Node;
import org.xbib.cql.elasticsearch.ast.Operator; import org.xbib.cql.elasticsearch.ast.Operator;
import org.xbib.cql.elasticsearch.ast.Token; import org.xbib.cql.elasticsearch.ast.Token;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.Stack; import java.util.Stack;
@ -18,24 +17,24 @@ import java.util.Stack;
*/ */
public class SortGenerator implements Visitor { public class SortGenerator implements Visitor {
private final XContentBuilder builder; private final JsonBuilder builder;
private final Stack<Modifier> modifiers; private final Stack<Modifier> modifiers;
public SortGenerator() throws IOException { public SortGenerator() {
this.builder = JsonXContent.contentBuilder(); this.builder = new JsonBuilder();
this.modifiers = new Stack<>(); this.modifiers = new Stack<>();
} }
public void start() throws IOException { public void start() throws IOException {
builder.startArray(); builder.beginCollection();
} }
public void end() throws IOException { public void end() throws IOException {
builder.endArray(); builder.endCollection();
} }
public XContentBuilder getResult() { public JsonBuilder getResult() {
return builder; return builder;
} }
@ -47,15 +46,15 @@ public class SortGenerator implements Visitor {
public void visit(Name node) { public void visit(Name node) {
try { try {
if (modifiers.isEmpty()) { if (modifiers.isEmpty()) {
builder.startObject() builder.beginMap()
.field(node.getName()) .buildKey(node.getName())
.startObject() .beginMap()
.field("unmapped_type", "string") .field("unmapped_type", "string")
.field("missing", "_last") .field("missing", "_last")
.endObject() .endMap()
.endObject(); .endMap();
} else { } else {
builder.startObject().field(node.getName()).startObject(); builder.beginMap().buildKey(node.getName()).beginMap();
while (!modifiers.isEmpty()) { while (!modifiers.isEmpty()) {
Modifier mod = modifiers.pop(); Modifier mod = modifiers.pop();
String s = mod.getName().toString(); String s = mod.getName().toString();
@ -71,15 +70,15 @@ public class SortGenerator implements Visitor {
break; break;
} }
default: { default: {
builder.field(s, mod.getTerm()); builder.field(s, mod.getTerm().toString());
break; break;
} }
} }
} }
builder.field("unmapped_type", "string"); builder.field("unmapped_type", "string");
builder.field("missing", "_last"); builder.field("missing", "_last");
builder.endObject(); builder.endMap();
builder.endObject(); builder.endMap();
} }
} catch (IOException e) { } catch (IOException e) {
throw new SyntaxException(e.getMessage(), e); throw new SyntaxException(e.getMessage(), e);

View file

@ -1,17 +1,15 @@
package org.xbib.cql.elasticsearch; package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder; import org.xbib.datastructures.json.tiny.JsonBuilder;
import org.xbib.content.core.DefaultXContentBuilder;
import org.xbib.content.json.JsonXContent;
import java.io.IOException; import java.io.IOException;
public class SourceGenerator { public class SourceGenerator {
private final XContentBuilder builder; private final JsonBuilder builder;
public SourceGenerator() throws IOException { public SourceGenerator() throws IOException {
this.builder = JsonXContent.contentBuilder(); this.builder = new JsonBuilder();
} }
public void build(QueryGenerator query) throws IOException { public void build(QueryGenerator query) throws IOException {
@ -23,8 +21,8 @@ public class SourceGenerator {
} }
public void build(QueryGenerator query, Integer from, Integer size, public void build(QueryGenerator query, Integer from, Integer size,
XContentBuilder sort, XContentBuilder facets) throws IOException { JsonBuilder sort, JsonBuilder facets) throws IOException {
builder.startObject(); builder.beginMap();
if (query != null) { if (query != null) {
if (from != null) { if (from != null) {
builder.field("from", from); builder.field("from", from);
@ -32,25 +30,23 @@ public class SourceGenerator {
if (size != null) { if (size != null) {
builder.field("size", size); builder.field("size", size);
} }
copy(builder, "query", query.getResult()); if (query.getResult() != null) {
copy(builder, "sort", sort); builder.buildKey("query");
copy(builder, "aggregations", facets); builder.copy(query.getResult());
} }
builder.endObject(); if (sort != null && sort.build().length() > 0) {
builder.close(); builder.buildKey("sort");
} builder.copy(sort);
}
public XContentBuilder getResult() { if (facets != null && facets.build().length() > 0) {
return builder; builder.buildKey("aggregations");
} builder.copy(facets);
private void copy(XContentBuilder builder, String rawFieldName, XContentBuilder anotherBuilder) throws IOException {
if (anotherBuilder != null) {
DefaultXContentBuilder contentBuilder = (DefaultXContentBuilder) anotherBuilder;
if (contentBuilder.bytes().length() > 0) {
byte[] b = contentBuilder.bytes().toBytes();
builder.rawField(rawFieldName, b, 0, b.length);
} }
} }
builder.endMap();
}
public JsonBuilder getResult() {
return builder;
} }
} }

View file

@ -7,12 +7,11 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/**
*
*/
class ElasticsearchQueryTest { class ElasticsearchQueryTest {
@Test @Test
@ -27,7 +26,7 @@ class ElasticsearchQueryTest {
parser.parse(); parser.parse();
ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes"); ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes");
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String json = generator.getResult().string(); String json = generator.getResult().build();
assertEquals(json, "{\"term\":{\"cql.allIndexes\":\"Jörg\"}}"); assertEquals(json, "{\"term\":{\"cql.allIndexes\":\"Jörg\"}}");
} }
@ -38,7 +37,7 @@ class ElasticsearchQueryTest {
parser.parse(); parser.parse();
ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes"); ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes");
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String json = generator.getResult().string(); String json = generator.getResult().build();
assertEquals(json, "{\"query\":{\"term\":{\"dc.type\":\"electronic\"}}}"); assertEquals(json, "{\"query\":{\"term\":{\"dc.type\":\"electronic\"}}}");
} }
@ -49,7 +48,7 @@ class ElasticsearchQueryTest {
parser.parse(); parser.parse();
ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes"); ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes");
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String json = generator.getResult().string(); String json = generator.getResult().build();
assertEquals( assertEquals(
"{\"query\":{\"bool\":{\"must\":[{\"term\":{\"dc.type\":\"electronic\"}},{\"term\":{\"dc.date\":\"2013\"}}]}}}", "{\"query\":{\"bool\":{\"must\":[{\"term\":{\"dc.type\":\"electronic\"}},{\"term\":{\"dc.date\":\"2013\"}}]}}}",
json json
@ -63,7 +62,7 @@ class ElasticsearchQueryTest {
parser.parse(); parser.parse();
ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes"); ElasticsearchFilterGenerator generator = new ElasticsearchFilterGenerator("cql.allIndexes");
parser.getCQLQuery().accept(generator); parser.getCQLQuery().accept(generator);
String json = generator.getResult().string(); String json = generator.getResult().build();
assertEquals( assertEquals(
"{\"query\":{\"bool\":{\"must\":[{\"bool\":{\"must\":[{\"term\":{\"dc.format\":\"online\"}}," + "{\"query\":{\"bool\":{\"must\":[{\"bool\":{\"must\":[{\"term\":{\"dc.format\":\"online\"}}," +
"{\"term\":{\"dc.type\":\"electronic\"}}]}},{\"term\":{\"dc.date\":\"2013\"}}]}}}", "{\"term\":{\"dc.type\":\"electronic\"}}]}},{\"term\":{\"dc.date\":\"2013\"}}]}}}",
@ -112,6 +111,8 @@ class ElasticsearchQueryTest {
} }
} catch (Exception e) { } catch (Exception e) {
errors++; errors++;
Logger.getAnonymousLogger().log(Level.SEVERE, line);
Logger.getAnonymousLogger().log(Level.SEVERE, e.getMessage(), e);
} }
count++; count++;
} }

View file

@ -1,6 +1,6 @@
group = org.xbib group = org.xbib
name = cql name = cql
version = 3.1.4 version = 4.0.0
gradle.wrapper.version = 6.6.1 gradle.wrapper.version = 6.6.1
xbib-content.version = 3.0.0 xbib-datastructures.version = 1.0.0