io.vertx.tp.plugin.elasticsearch.ElasticSearchHelper Maven / Gradle / Ivy
package io.vertx.tp.plugin.elasticsearch;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.tp.error._404ConfigurationMissingExceptionn;
import io.vertx.up.fn.Fn;
import io.vertx.up.log.Annal;
import io.vertx.up.util.Ut;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
/**
* @author Hongwei
* @since 2019/12/29, 13:31
*/
public class ElasticSearchHelper {
private static final Annal LOGGER = Annal.get(ElasticSearchHelper.class);
private transient final Class> target;
private ElasticSearchHelper(final Class> target) {
this.target = target;
}
static ElasticSearchHelper helper(final Class> target) {
return Fn.pool(Pool.HELPERS, target.getName(), () -> new ElasticSearchHelper(target));
}
RestHighLevelClient getClient(final JsonObject options) {
Fn.outWeb(Ut.isNil(options), _404ConfigurationMissingExceptionn.class, this.getClass());
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(options.getString("username"), options.getString("password"))
);
return new RestHighLevelClient(
RestClient.builder(
new HttpHost(options.getString("hostname"), options.getInteger("port"), options.getString("scheme"))
)
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(final HttpAsyncClientBuilder httpAsyncClientBuilder) {
httpAsyncClientBuilder.disableAuthCaching();
return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
.setMaxConnTotal(100)
.setMaxConnPerRoute(100);
}
})
.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(final RequestConfig.Builder builder) {
return builder.setConnectionRequestTimeout(60000)
.setConnectTimeout(60000)
.setSocketTimeout(60000);
}
})
);
}
void closeClient(final RestHighLevelClient client) {
try {
client.close();
} catch (final IOException ioe) {
LOGGER.error("error occurred when close elasticsearch connection", ioe.getMessage());
}
}
Settings settingsBuilder(final int numberOfShards, final int numberOfReplicas) {
return Settings.builder()
.put("index.number_of_shards", numberOfShards > 0 ? numberOfShards : 3)
.put("index.number_of_replicas", numberOfReplicas > 0 ? numberOfReplicas : 2)
.build();
}
/**
* build mappings for index from fields and fields' type
*
* @param mappings fields with type, format like below
* {
* "field": "String",
* ...
* }
*
* @return translated map object
*/
Map mappingsBuilder(final ConcurrentMap> mappings) {
final Map properties = new HashMap<>();
// process field: key
if (mappings.containsKey("key")) {
final Map keyProp = new HashMap<>();
keyProp.put("type", "keyword");
keyProp.put("index", true);
properties.put("key", keyProp);
mappings.remove("key");
}
// process rest fields
mappings.forEach((key, val) -> {
final Map props = new HashMap<>();
if (val == JsonObject.class || val == JsonArray.class) {
/*
* Default un-index JsonObject/JsonArray two types
* Disabled JsonObject / JsonArray index workflow for Elastic Search
* It will be enabled in future, but in current version, disabled
*/
props.put("type", "text");
props.put("index", "false");
} else if (val == String.class) {
props.put("type", "text");
props.put("index", "true");
props.put("analyzer", "ik_max_word");
} else if (val == java.time.LocalTime.class || val == java.time.LocalDateTime.class ||
val == java.time.LocalDate.class || val == java.time.Instant.class) {
props.put("type", "date");
props.put("index", "true");
props.put("format", "yyyy-MM-dd||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd'T'HH:mm:ss'Z'||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis");
} else if (val == java.lang.Integer.class) {
props.put("type", "integer");
props.put("index", "true");
} else if (val == java.lang.Long.class) {
props.put("type", "long");
props.put("index", "true");
} else if (val == java.lang.Double.class || val == java.lang.Float.class || val == java.math.BigDecimal.class) {
props.put("type", "double");
props.put("index", "true");
;
} else if (val == java.lang.Boolean.class) {
props.put("type", "boolean");
props.put("index", "true");
} else {
props.put("type", "text");
props.put("index", "true");
props.put("analyzer", "ik_max_word");
}
properties.put(key, props);
});
final Map result = new HashMap<>();
result.put("properties", properties);
return result;
}
SearchSourceBuilder searchSourceBuilder(final String searchText, final ConcurrentMap precision, final int from, final int size) {
final QueryStringQueryBuilder textCond = QueryBuilders.queryStringQuery(searchText);
/* Condition for precision */
final SearchSourceBuilder builder = new SearchSourceBuilder();
if (Objects.isNull(precision) || precision.isEmpty()) {
/*
* No precision map set
*/
builder.query(textCond);
LOGGER.debug("[ ZERO ] Final query condition: {0}", textCond.toString());
} else {
/*
* Precision Condition
*/
final BoolQueryBuilder condition = QueryBuilders.boolQuery();
precision.forEach((field, value) -> {
final MatchPhraseQueryBuilder fieldCond = QueryBuilders.matchPhraseQuery(field, value);
condition.must(fieldCond);
});
/*
* Final Query Builder
*/
final BoolQueryBuilder finalCond = QueryBuilders.boolQuery();
finalCond.must(condition).must(textCond);
builder.query(finalCond);
LOGGER.debug("[ ZERO ] Final query condition with precision: {0}", finalCond.toString());
}
return builder.aggregation(AggregationBuilders.terms(Aggregations.AGGREGATIONS_FIELD).field("_index"))
.highlighter(new HighlightBuilder().field("*").preTags("").postTags("").highlighterType("unified"))
.from(Math.max(0, from))
.size(Math.max(10, size))
.timeout(new TimeValue(10, TimeUnit.SECONDS));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy