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 {
api project(':cql-common')
implementation "org.xbib:content-core:${project.property('xbib-content.version')}"
implementation "org.xbib:content-json:${project.property('xbib-content.version')}"
implementation "org.xbib:datastructures-json-tiny:${project.property('xbib-datastructures.version')}"
}

View file

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

View file

@ -1,6 +1,5 @@
package org.xbib.cql.elasticsearch;
import org.xbib.content.XContentBuilder;
import org.xbib.cql.BooleanGroup;
import org.xbib.cql.BooleanOperator;
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.TokenType;
import org.xbib.cql.elasticsearch.model.ElasticsearchQueryModel;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import java.io.IOException;
import java.time.ZonedDateTime;
@ -45,7 +45,7 @@ public class ElasticsearchFilterGenerator implements Visitor {
private final String globalField;
private FilterGenerator filterGen;
private final FilterGenerator filterGen;
public ElasticsearchFilterGenerator(String globalField) {
this(globalField, new ElasticsearchQueryModel());
@ -55,11 +55,7 @@ public class ElasticsearchFilterGenerator implements Visitor {
this.globalField = globalField;
this.model = model;
this.stack = new Stack<>();
try {
this.filterGen = new FilterGenerator();
} catch (IOException e) {
// ignore
}
}
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();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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