elasticsearch QueryBuilder with dynamic list value in term query - java

I have a code like below where I'm doing multiple must in bool query. Here I'm passing the must term queries in field "address". Now the ip address will come to me as a list from other api and I have to pass for all the ip's in the list as a must term query. Here I'm not getting a way how to pass the address values dynamically when creating the QueryBuilder.
Please suggest how to do this.
public static SearchResponse searchResultWithAggregation(String es_index,
String es_type, List<String> ipList, String queryRangeTime) {
Client client = ESClientFactory.getInstance();
QueryBuilder qb = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("address", "10.203.238.138"))
.must(QueryBuilders.termQuery("address", "10.203.238.137"))
.must(QueryBuilders.termQuery("address", "10.203.238.136"))
.mustNot(QueryBuilders.termQuery("address", "10.203.238.140"))
.should(QueryBuilders.termQuery("client", ""));
queryRangeTime = "now-" + queryRangeTime + "m";
FilterBuilder fb = FilterBuilders.rangeFilter("#timestamp")
.from(queryRangeTime).to("now");
SearchResponse response = client
.prepareSearch(es_index)
.setTypes(es_type)
.setQuery(qb)
.setPostFilter(fb)
.addAggregation(
AggregationBuilders.avg("cpu_average").field("value"))
.setSize(10).execute().actionGet();
System.out.println(response.toString());
return response;
}

You can use the terms query to pass multiple values for single field.
create a string array or set. and pass it to the terms query.
Set<String> address = new HashSet<String>();
address.add("10.203.238.138");
address.add("10.203.238.137");
address.add("10.203.238.136");
if(address!=null)
QueryBuilder qb = QueryBuilders.boolQuery()
.must(QueryBuilders.termsQuery("address",address))
.mustNot(QueryBuilders.termQuery("address", "10.203.238.140"))
.should(QueryBuilders.termQuery("client", ""));
else
QueryBuilder qb = QueryBuilders.boolQuery()
.mustNot(QueryBuilders.termQuery("address", "10.203.238.140"))
.should(QueryBuilders.termQuery("client", ""));
Hope it helps..!

If you use TermsQuery for address array/set, it will return any documents that match with at least one or more of the provided terms.
List<String> address = new ArrayList<String>();
address.add("10.203.238.138");
address.add("10.203.238.137");
address.add("10.203.238.136");
BoolQueryBuilder qb = QueryBuilders.boolQuery();
qb.mustNot(QueryBuilders.termQuery("address", "10.203.238.140"));
qb.should(QueryBuilders.termQuery("client", ""));
for(String add: Address){
qb.must(QueryBuilders.termsQuery("address",add));
}

Related

Fetch all record including particular fields

I am working with Elasticcsearch 7.3. I want to fetch only two records of all the documents using JAVA Api from my index. I am using the following code but it returning the null object.
RestHighLevelClient client;
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.fetchSource("recipe_ID,recipe_url", null);
sourceBuilder.from(0);
SearchRequest searchRequest = new SearchRequest("recipes");
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit searchHit = searchResponse.getHits().getAt(0);
String resultString = searchHit.getSourceAsString();
return resultString;
I need to include only two fields recipe_ID and recipe_url in my result.
You're on the right path, although source filtering requires you to specify your fields in an array like this:
String[] includeFields = new String[] {"recipe_ID", "recipe_url"};
sourceBuilder.fetchSource(includeFields, null);

How to AND multiple setQuery in elasticsearch using java?

I am trying to create query for search filter using elasticsearch. I created query that shows results based on search term, price range and brand list. Results shown for searchterm and price range is right but when brand list is provided all results related to selected brand is shown.
I want results for searchterm AND price AND brands
This is my query
BoolQueryBuilder query = QueryBuilders.boolQuery();
for (String key : brands) {
query.must(QueryBuilders.matchQuery("brand", key));
}
SearchResponse searchresponse = client
.prepareSearch("product")
.setTypes("product")
.setQuery(
QueryBuilders.matchPhraseQuery("name", pSearchTerm))
.setPostFilter(
QueryBuilders.rangeQuery("unit_price").from(min)
.to(max))
.setQuery(query).setExplain(true)
.execute().actionGet();
what am i doing wrong here?
You have two setQuery() calls so the second one is overriding the first one. You need to combine all your constraints into one query like this:
// brand list
BoolQueryBuilder query = QueryBuilders.boolQuery();
for (String key : brands) {
query.must(QueryBuilders.matchQuery("brand", key));
}
// search term
query.must(QueryBuilders.matchPhraseQuery("name", pSearchTerm));
// price range
query.filter(QueryBuilders.rangeQuery("unit_price").from(min).to(max));
SearchResponse searchresponse = client
.prepareSearch("product")
.setTypes("product")
.setQuery(query)
.setExplain(true)
.execute().actionGet();

Search and filter with Spring Data Elasticsearch

I have a JPA entity called Invoice with some properties and want to search and filter the results, but the filter is not working properly. I tried various combinations but no one worked for me.
This one correctly searches for instances having "foobar" in some of the properties:
// this is the search string...
String search = "foobar*";
QueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(search);
NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
searchQuery.withQuery(queryStringQuery);
// build and run against the ElasticsearchRepository
NativeSearchQuery query = searchQuery.build();
Page<T> result = searchRepository.search(query);
This is working and gives me all invoices, but now I only want to have "new invoices", which is given by a property called "state", which then has the value "New".
Currently, last one I tried is this one (according to similar questions on SO):
String search = "foobar*";
QueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(search);
NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
searchQuery.withQuery(queryStringQuery);
// add filter
QueryBuilder filters = QueryBuilders.termQuery("state", "New");
searchQuery.withFilter(searchFilters);
// build and run against the ElasticsearchRepository
NativeSearchQuery query = searchQuery.build();
Page<T> result = searchRepository.search(query);
This one gives me an empty result, although there must be some results.
I also tried to create somthing like this, but this is also not working:
String search = "foobar*";
QueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(search);
searchFilters = QueryBuilders.termQuery("state", "New");
BoolQueryBuilder searchQuery = QueryBuilders.boolQuery().should(queryStringQuery).must(searchFilters);
Iterable<T> result = searchRepository.search(searchQuery);
Use something like this
QueryBuilder qb;
QueryBuilder stateFilters = QueryBuilders.boolQuery();
((BoolQueryBuilder) filters).filter(QueryBuilders.matchQuery("state", "New"));
qb = QueryBuilders.boolQuery().should(QueryBuilders.queryStringQuery("foobar*")).filter(stateFilters );
the filter function here helps us with this
here qb will have the proper query which can now be used to search using the elasticsearchRepository.search(qb);
Here is some information from spring docs:
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.operations

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"));

Using Hibernate Search (Lucene) to query a term with no spaces to match against field value with spaces

I have a Movie class with a name field. I want to match against movie names that have spaces in it for query terms with no spaces.
For example: I want the movie with name Toy Story to be in the results when the search term is toystory.
How to do I write my Hibernate Search DSL Query?
One way of addressing this is actually an index time solution. You could add the movie title as concatenated (w/o spaces) string to the the index using a custom analyzer. This way you would get the functionality you are after for free.
Add an analyzer to the Movie class with a NGramFilterFactory and LowerCaseFilterFactory filters, then use this analyzer for the name field:
#Indexed
#AnalyzerDef(name = "ngram", tokenizer = #TokenizerDef(factory = StandardTokenizerFactory.class), filters = {
#TokenFilterDef(factory = LowerCaseFilterFactory.class),
#TokenFilterDef(factory = NGramFilterFactory.class, params = {
#Parameter(name = "minGramSize", value = "3"),
#Parameter(name = "maxGramSize", value = "10")
})
})
public class Movie{
#Field( analyze = Analyze.YES )
#Analyzer( definition="ngram" )
private String name;
// standard setters and getters go here
}
The movie with name Toy Story will definitely appear in the results when the search term is toystory, just use the next query:
QueryBuilder qb = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Movie.class ).get();
org.apache.lucene.search.Query query = qb
.keyword()
.onField("name")
.matching("toystory");
.createQuery();
org.hibernate.Query hibQuery =
fullTextSession.createFullTextQuery(query, Movie.class);
List result = hibQuery.list();

Categories

Resources