Query Elasticsearch using String in java - java

I am using Elasticsearch maven jar file to query Elasticsearch. But now I want to query the elasticsearch using full generated query string:
query :
{
"bool" : {
"must" : [ {
"term" : {
"title" : "mercedes"
}
}, {
"term" : {
"Doors" : "2"
}
} ]
}
}
How do I use the above query string to query elasticsearch in java?

Following code prepares a boolquery. You should create a SearchRequestBuilder to execute it.
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
boolQuery.must(QueryBuilders.termQuery("title", "mercedes"));
boolQuery.must(QueryBuilders.termQuery("Doors", "2"));
If you want to use query as string without building it in code, you can use following;
String myQuery = "Your Query Here";
SearchSourceBuilder ssb= new SearchSourceBuilder();
search.query(myQuery);
SearchRequestBuilder srb; // You should define srb before next steps
srb.internalBuilder(ssb);
SearchResponse response = srb.execute().actionGet();

I use the following code to query Elasticsearch using JSON string.
SearchResponse response = client.prepareSearch(yourIndexName)
.setSource(yourJsonQueryString)
.execute().actionGet();

Related

Elasticsearch wildcard query in Java - find all matching fields and replace

I want to update all path fields starting with "example/one".
Map<String, Object> parameters = new HashMap<>();
parameters.put("old", "example/one");
parameters.put("new", "new/example");
UpdateByQueryRequest request = new UpdateByQueryRequest(index)
.setDocTypes(type)
.setScript(new Script(ScriptType.INLINE,
"painless",
"ctx._source.path = ctx._source.path.replace(params.old, params.new);",
parameters))
.setQuery(QueryBuilders.wildcardQuery("path.tree", "example/one*"));
client.updateByQuery(request, RequestOptions.DEFAULT);
It's not working (no update, no errors - tried a prefixQuery, same). The following query however is updating the matching documents (Postman).
POST my_index/_update_by_query
{
"script": {
"lang": "painless",
"inline": "ctx._source.path = ctx._source.path.replace(\"example/one\", \"new/example\")"
},
"query": {
"wildcard": {
"path.tree": {
"value: "example/one*",
"boost": 1.0,
"rewrite": "constant_score"
}
}
}
}
What am I missing? The Path hierarchy tokenizer is used on the field path.
Your help is much needed.
PS: I can't upgrade to a newer version of elasticsearch.
When testing the solution, I first thought it was related to the custom analyser used on the path field. But it was quickly discarded as I was getting the expected result via Postman.
I finally decided to go with a 'two steps' solution (couldn't use the update by query API). First search for all matching documents, then perform a bulk update.
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.wildcardQuery("path.tree", "example/one*"))
.withSourceFilter(new FetchSourceFilter(new String[]{"_id", "path"}, null))
.build();
List<MyClass> result = elasticsearchRestTemplate.queryForList(query, MyClass.class);
if(!CollectionUtils.isEmpty(result)) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("old", "example/one");
parameters.put("new", "new/example");
Script script = new Script(ScriptType.INLINE,
"painless",
"ctx._source.path = ctx._source.path.replace(params.old, params.new)",
parameters);
BulkRequest request = new BulkRequest();
for (MyClass myClass : result) {
request.add(new UpdateRequest(index, type, myClass.getId()).script(script));
}
client.bulk(request, RequestOptions.DEFAULT);
}
UPDATE
Turns out setting the type in the request was the problem.
UpdateByQueryRequest request = new UpdateByQueryRequest(index)
.setDocTypes(type) <--------------- Remove
.....

How to use QueryStringQueryBuilder

I've tried to use QueryStringQueryBuilder in a very simple case, but I dont understand why I get another result than the result I get from Kibana. What am I doing wrong?
Kibana:
GET .../_search
{
"query": {
"query_string" : {
"query" : "\"this is a query\"",
"lenient": true,
"default_operator": "OR"
}
}
}
Java:
private Optional<QueryStringQueryBuilder> parseQuery(String query) {
if (query.equals("")) {
return Optional.empty();
}
QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(query);
queryBuilder.lenient(true);
queryBuilder.defaultOperator(Operator.OR);
return Optional.of(queryBuilder);
}
Result from kibana: totalhits = 3336. Result from Java: totalhits = 10018.
EDIT:
This method calls parseQuery. Input is "this is a query".
public Optional<SearchRequestBuilder> getRequestBuilderByQuery(SearchQuery query) {
SearchRequestBuilder builder = getBuilderWithMaxHits(query.getMaxHits());
builder.setFetchSource(Globals.getFIELDS(query.isIncludeStory()), new String[0]);
parseQuery(query.getQuery()).ifPresent(builder::setQuery);
return Optional.of(builder);
}
I dont know what your input parameter 'query' in this case contains.
But i think you want to set queryBuilder.queryName(String queryName) in your QueryStringQueryBuilder.
From the JavaDocs:
queryName(String queryName):
Sets the query name for the filter that can be used when searching for matched_filters per hit.
Ok, I found the problem.
The query for kibana had quotation marks. Which meant it was processed differently than just a normal String. QueryStringQuerybuilder seems to be parsing the query by itself with "",AND,OR,NOT. This is magic!

BasicDBObjectBuilder not appending mutiple criteria for a single object

I am using Java driver for mongo-db and trying to add multiple query criteria using BasicDBObjectBuilder. I have a text field where an XML is stored as String so we are using regex to form the query.
Below is my query and the output I am getting:
regexQuery.put("REQUEST_XML",BasicDBObjectBuilder
.start("$regex", ".*Main>[\r\n]<.?.?.?.?action>"+MainValue+".*")
.add("$regex", ".*Details>[\r\n]<.?.?.?.?action>" + DetailValue+ ".*").get());
regexQuery.put("NAME", "Video");
What I am getting as query is :
{ "REQUEST_XML" : { "$regex" : ".*Details>[\r\n]<.?.?.?.?action>Change.*"} , "NAME" : "Video"}
The first part with .start("$regex", ".Main>[\r\n]<.?.?.?.?action>"+MainValue+".") is not getting added to query.
Can you please let me know what is the issue ?
You are overwriting the key value pair. "$regex", ".*Details>[\r\n]<.?.?.?.?action>" + DetailValue+ ".*" overwrites "$regex", ".*Main>[\r\n]<.?.?.?.?action>"+MainValue+".*".
Use $or to pass both regex expression.
Something like
BasicDBObject regexQuery = new BasicDBObject();
regexQuery.put("$or", Arrays.asList(new BasicDBObject("REQUEST_XML", new BasicDBObject("$regex", ".*Main>[\r\n]<.?.?.?.?action>"+".*")),
new BasicDBObject("REQUEST_XML", new BasicDBObject("$regex", ".*Details>[\r\n]<.?.?.?.?action>"+".*"))));
regexQuery.put("NAME", "Video");
This should output query like
{ "$or" : [{ "REQUEST_XML" : { "$regex" : ".*Main>[\r\n]<.?.?.?.?action>.*" } }, { "REQUEST_XML" : { "$regex" : ".*Details>[\r\n]<.?.?.?.?action>.*" } }], "NAME" : "Video" }
Using 3.x driver
import static com.mongodb.client.model.Filters.or;
import static com.mongodb.client.model.Filters.regex;
Bson regexQuery = or(regex("REQUEST_XML", ".*Main>[\r\n]<.?.?.?.?action>"+".*"), regex("$regex", ".*Details>[\r\n]<.?.?.?.?action>"+".*"));

Search By multiple word using AND operator

This works like a charm :
Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("localhost", 9300));
FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("field", "word_1");
fuzzyQueryBuilder.fuzziness(Fuzziness.AUTO);
SearchResponse response = client.prepareSearch("ts_index")
.setTypes("service")
.setQuery(fuzzyQueryBuilder)
.setFrom(0).setSize(60).setExplain(true)
.execute()
.actionGet();
SearchHit[] results = response.getHits().getHits();
But if I want to search by multiple words, it returns nothing, Ex :
FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("field", "word_1 word_2");
When I'm using CURL, I've resolved this issue by adding operator to my JSON attributes:
curl -XGET "http://localhost:9200/_search" -d" {\"query\":{\"match\":{\"field\":{\"query\":\"word_1 word_2\",\"fuzziness\":\"AUTO\",\"operator\":\"and\"}}}}
How can I achieve this in Java ?
I believe this is possible with must for AND and should for OR:
QueryBuilder qb = QueryBuilders.boolQuery()
.must(QueryBuilders.fuzzyQuery("field", "word_1"))
.must(QueryBuilders.fuzzyQuery("field", "word_2"));
You can try to build this in a dynamic way with an enum:
public enum MultiQueryBuilder {
OPERATOR_AND {
#Override
public QueryBuilders createQuery(String field, String multiWord) {
String[] words = multiWord.split("\\s+");
QueryBuilder queryBuilder = QueryBuilder.boolQuery();
for(String word : words){
queryBuilder.must(QueryBuilders.fuzzyQuery(field, word));
}
return queryBuilder;
},
OPERATOR_OR {
#Override
public QueryBuilders createQuery(String field, String multiWord) {
String[] words = multiWord.split("\\s+");
QueryBuilder queryBuilder = QueryBuilder.boolQuery();
for(String word : words){
queryBuilder.should(QueryBuilders.fuzzyQuery(field, word));
}
return queryBuilder;
};
public abstract Querybuilders createQuery(String field, String multiWord);
}
You just have to call it in this way:
FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders
.fuzzyQuery(MultiQuerybuilder
.valueOf(OPERATOR_AND)
.createQuery("field", "word_1 word_2"));

How to create a query with query_string using Elasticsearch Java Api

Currently my query request body looks like
{
"query": {
"query_string": {
"default_field": "file",
"query": "Email OR #gmail.com #yahoo.com"
}
},
"highlight": {
"fields": {
"file": {
}
}
}
}
My java code looks like
String queryString = "{"
+ "\"query_string\": "
+ "{"
+ "\"default_field\":"
+ " \"file\","
+ " \"query\": \"Email OR #gmail.com #yahoo.com\""
+ "}"
+ "}";
with following API calls
SearchRequestBuilder searchRequestBuilder = client.prepareSearch()
.setIndices("resume")
.setTypes("docs").setQuery(queryString).addHighlightedField("file");
SearchResponse response = searchRequestBuilder.execute().actionGet();
I would prefer a more api based approach for "queryString" part.I am not able to find any api which handles "query_string" part of the request. There are apis for match_all,match, term so on and so forth but not for query_string
Any help would be really appreciated
QueryBuilders is the factory for creating any query including query_string. From documentation:
import static org.elasticsearch.index.query.QueryBuilders.*;
QueryBuilder qb = queryStringQuery("+kimchy -elasticsearch");
Your query would be built as follows:
QueryBuilder qb = queryStringQuery("Email OR #gmail.com #yahoo.com").defaultField("file");
And the full example would be:
SearchRequestBuilder searchRequestBuilder = client.prepareSearch()
.setIndices("resume")
.setTypes("docs").setQuery(qb).addHighlightedField("file");
SearchResponse response = searchRequestBuilder.execute().actionGet();

Categories

Resources