Skip to content

Commit

Permalink
Search in Elasticsearch by criteria
Browse files Browse the repository at this point in the history
  • Loading branch information
rgomezcasas committed Nov 18, 2019
1 parent 3df63eb commit 6518cc0
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 5 deletions.
28 changes: 27 additions & 1 deletion doc/endpoints/backoffice_frontend.http
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,33 @@ Content-Type: application/json
{
"query": {
"term": {
"name": "Pepe"
"name": "git avanzado"
}
}
}

###

# ELASTIC - debug
POST localhost:9200/backoffice_courses/_search
Content-Type: application/json

{
"from": 0,
"size": 1000,
"query": {
"bool": {
"must": [
{
"term": {
"name": {
"value": "pepe2"
}
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"index": true
},
"name": {
"type": "text",
"index": true
"type": "string",
"index": "not_analyzed"
},
"duration": {
"type": "text",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public List<BackofficeCourse> searchAll() {

@Override
public List<BackofficeCourse> matching(Criteria criteria) {
return searchAllInElastic(BackofficeCourse::fromPrimitives);
return searchByCriteria(criteria, BackofficeCourse::fromPrimitives);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ public Optional<Integer> limit() {
public Optional<Integer> offset() {
return offset;
}

public boolean hasFilters() {
return filters.filters().size() > 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ public static FilterOperator fromValue(String value) {
default: return null;
}
}

public boolean isPositive() {
return this != NOT_EQUAL && this != NOT_CONTAINS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ public boolean isNone() {
public boolean isAsc() {
return this == ASC;
}

public String value() {
return type;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package tv.codely.shared.infrastructure.elasticsearch;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import tv.codely.shared.domain.criteria.Criteria;
import tv.codely.shared.domain.criteria.Filter;
import tv.codely.shared.domain.criteria.FilterOperator;
import tv.codely.shared.domain.criteria.Filters;

import java.util.HashMap;
import java.util.function.Function;

public final class ElasticsearchCriteriaConverter {
private final HashMap<FilterOperator, Function<Filter, QueryBuilder>> queryTransformers = new HashMap<FilterOperator, Function<Filter, QueryBuilder>>() {{
put(FilterOperator.EQUAL, ElasticsearchCriteriaConverter.this::termQuery);
put(FilterOperator.NOT_EQUAL, ElasticsearchCriteriaConverter.this::termQuery);
put(FilterOperator.GT, ElasticsearchCriteriaConverter.this::greaterThanQueryTransformer);
put(FilterOperator.LT, ElasticsearchCriteriaConverter.this::lowerThanQueryTransformer);
put(FilterOperator.CONTAINS, ElasticsearchCriteriaConverter.this::wildcardTransformer);
put(FilterOperator.NOT_CONTAINS, ElasticsearchCriteriaConverter.this::wildcardTransformer);
}};

public SearchSourceBuilder convert(Criteria criteria) {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

sourceBuilder.from(criteria.offset().orElse(0));
sourceBuilder.size(criteria.limit().orElse(1000));

if (criteria.order().hasOrder()) {
sourceBuilder.sort(
criteria.order().orderBy().value(),
SortOrder.fromString(criteria.order().orderType().value())
);
}

if (criteria.hasFilters()) {
QueryBuilder queryBuilder = generateQueryBuilder(criteria.filters());

sourceBuilder.query(queryBuilder);
}

return sourceBuilder;
}

private QueryBuilder generateQueryBuilder(Filters filters) {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

for (Filter filter : filters.filters()) {
QueryBuilder query = queryForFilter(filter);

if (isPositiveOperator(filter.operator())) {
boolQueryBuilder.must(query);
} else {
boolQueryBuilder.mustNot(query);
}
}

return boolQueryBuilder;
}

private boolean isPositiveOperator(FilterOperator operator) {
return operator.isPositive();
}

private QueryBuilder queryForFilter(Filter filter) {
Function<Filter, QueryBuilder> transformer = queryTransformers.get(filter.operator());

return transformer.apply(filter);
}

private QueryBuilder termQuery(Filter filter) {
return QueryBuilders.termQuery(filter.field().value(), filter.value().value().toLowerCase());
}

private QueryBuilder greaterThanQueryTransformer(Filter filter) {
return QueryBuilders.rangeQuery(filter.field().value()).gt(filter.value().value().toLowerCase());
}

private QueryBuilder lowerThanQueryTransformer(Filter filter) {
return QueryBuilders.rangeQuery(filter.field().value()).lt(filter.value().value().toLowerCase());
}

private QueryBuilder wildcardTransformer(Filter filter) {
return QueryBuilders.wildcardQuery(filter.field().value(), String.format("*%s*", filter.value().value().toLowerCase()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import tv.codely.shared.domain.criteria.Criteria;

import java.io.IOException;
import java.io.Serializable;
Expand All @@ -12,15 +14,24 @@

public abstract class ElasticsearchRepository<T> {
private final ElasticsearchClient client;
private final ElasticsearchCriteriaConverter criteriaConverter;

public ElasticsearchRepository(ElasticsearchClient client) {
this.client = client;
this.criteriaConverter = new ElasticsearchCriteriaConverter();
}

abstract protected String moduleName();

protected List<T> searchAllInElastic(Function<Map<String, Object>, T> unserializer) {
SearchRequest request = new SearchRequest(client.indexFor(moduleName()));
return searchAllInElastic(unserializer, new SearchSourceBuilder());
}

protected List<T> searchAllInElastic(
Function<Map<String, Object>, T> unserializer,
SearchSourceBuilder sourceBuilder
) {
SearchRequest request = new SearchRequest(client.indexFor(moduleName())).source(sourceBuilder);
try {
SearchResponse response = client.highLevelClient().search(request, RequestOptions.DEFAULT);

Expand All @@ -34,6 +45,10 @@ protected List<T> searchAllInElastic(Function<Map<String, Object>, T> unserializ
return Collections.emptyList();
}

protected List<T> searchByCriteria(Criteria criteria, Function<Map<String, Object>, T> unserializer) {
return searchAllInElastic(unserializer, criteriaConverter.convert(criteria));
}

protected void persist(String id, HashMap<String, Serializable> plainBody) {
try {
client.persist(moduleName(), id, plainBody);
Expand Down

0 comments on commit 6518cc0

Please sign in to comment.