Elasticsearch 2+ JAVA API orFilter - java

I am trying to write some Java code to query an ES5 instance. In ES1, you could OR and AND filters, orFilter and andFilter. What is the equivalent in ES5? I have tried -
QueryBuilder fb1 = QueryBuilders.termQuery("term1", "value1");
QueryBuilder fb2 = QueryBuilders.termQuery("term1", "value2");
QueryBuilder fb3 = QueryBuilders.termQuery("term2", "value3");
QueryBuilder fb = QueryBuilders.boolQuery()
.must(fb1)
.should(fb2)
This gives results that match fb1, so this is not an OR
QueryBuilder fb = QueryBuilders.boolQuery()
.must(fb1)
.must(fb2)
This gives no results, so the AND worked.
I want to figure out ways of constructing AND, OR queries

In order to make an AND query, put all the conditions into "must".
QueryBuilder fb = QueryBuilders.boolQuery().must(fb1).must(fb2);
In order to make an OR query, put all the conditions into "should".
QueryBuilder fb = QueryBuilders.boolQuery().should(fb1).should(fb2);

From ElasticSearch documentation (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-compound-queries.html):
QueryBuilder qb = boolQuery()
.must(termQuery("content", "test1"))
.must(termQuery("content", "test4"))
.mustNot(termQuery("content", "test2"))
.should(termQuery("content", "test3"))
.filter(termQuery("content", "test5"));
must seems like it might be the equivalent of the AND and should like it's the equivalent of the OR.

You can use BoolQueryBuiler for these filters :
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("customerId", customerId))
boolQueryBuilder.mustNot(QueryBuilders.termsQuery("reason", "failed"));
boolQueryBuilder.should(QueryBuilders.termsQuery("action", "deny")).minimumNumberShouldMatch(1);
QueryBuilder queryBuilder=boolQueryBuilder;
new SearchContext().prepareSearch(sc.getIndexNames()).setTypes(sc.getTypeName()).setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setQuery(queryBuilder);

Related

How to filter a search query on multiple fields?

I have a list of studies. And I want to search over them with a typeahead function in a front page.
For that I use Hibernate Search with Spring Boot (2.1.5).
I indexed my STUDY table and some fields are marked with #Field attribute to be indexed.
The search works well.
But now I want to add a filter to use the same typeahead function but searching of a subset of my studies.
For that I created a filter like the Hibernate Search documentation but I didn't found a way to filter on two field with a OR between them.
My actual filter but filtering only on one field (avisDefinitifCet):
/**
* etudeFilter
*/
public class EtudeFilterFactory {
private String clasCet1ErPassage;
private String avisDefinitifCet;
public void setClasCet1ErPassage(String clasCet1ErPassage) {
this.clasCet1ErPassage = clasCet1ErPassage;
}
public void setAvisDefinitifCet(String avisDefinitifCet) {
this.avisDefinitifCet = avisDefinitifCet;
}
#Factory
public Query getFilter() {
System.out.println("Filter avisDefinitifCet : " + this.avisDefinitifCet.toLowerCase());
return new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase()));
}
}
How can I filter with a second field in my case clasCet1ErPassage?
At this end make a search on the standard search query and applying the filter like this
SELECT *
FROM STUDY
WHERE
A=t OR B=t OR C=t -- Normal search
AND (avisDefinitifCet='acceptation' OR clasCet1ErPassage='acceptation') -- Filter on two fields
My search function:
public List<Etude> search(String text, Map<String, String> allParams) {
text = stripAccents(text);
// get the full text entity manager
FullTextEntityManager fullTextEntityManager = getFullTextEntityManager(entityManager);
// create the query using Hibernate Search query DSL
QueryBuilder queryBuilder = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(Etude.class)
.get();
// Simple Query String queries
Query query = queryBuilder
.simpleQueryString()
.onFields("n0Cet")
.andField("anneeCet")
.andField("noDansAnneeCet")
.andField("sigleEtude")
.andField("titreEtude")
.andField("traitement1")
.andField("traitement2")
.andField("traitement3")
.andField("traitement4")
.andField("traitement5")
.andField("demandeurIgr.nomInvestigateurIgr")
.andField("investigateurHorsIgr.nomInvestigateur")
.andField("investigateurIgr.nomInvestigateurIgr")
.andField("promoteur.nomPromoteur")
.matching(text)
.createQuery();
// wrap Lucene query in an Hibernate Query object
FullTextQuery fullTextQuery = fullTextEntityManager
.createFullTextQuery(query, Etude.class)
.setMaxResults(101);
// Here allParams contains
// avisDefinitifCet => 'acceptation',
// clasCet1ErPassage => 'acceptation'
allParams.forEach((key, value) -> {
fullTextQuery.enableFullTextFilter("etudeFilter").setParameter(key, value);
});
return (List<Etude>) fullTextQuery.getResultList();
}
Am I thinking in the right way to implement it or I'm going wrong?
EDIT: Appparently you're using full-text filters, where you indeed have to use Lucene APIs directly.
In this case, just use a boolean junction with "should" clauses. When there's only "should" clauses in a boolean junction, at least one of them has to match.
#Factory
public Query getFilter() {
String valueToMatch = this.avisDefinitifCet.toLowerCase();
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", valueToMatch)), Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", valueToMatch)), Occur.SHOULD)
.build();
}
Previous answer:
If you're new to Lucene, you really should give the Hibernate Search DSL a try.
In your case, you'll want a keyword query that targets two fields:
EntityManager em = ...;
FullTextEntityManager fullTextEntityManager =
org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder().forEntity( Etude.class ).get();
Query luceneQuery = queryBuilder.keyword()
.onField("avisDefinitifCet").andField("clasCet1ErPassage")
.matching("acceptation")
.createQuery();
Note that, despite the method being called andField, it's actually an "OR": the query will match if any field matches.
For more advanced combination of queries, have a look at boolean junctions.
Here what I used to solve my problem thanks to #yrodiere
#Factory
public Query getFilter() {
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase())), BooleanClause.Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", this.clasCet1ErPassage.toLowerCase())), BooleanClause.Occur.SHOULD)
.build();
}

Elastic searchquery by multiple value

I am using java QueryBuilder to search values in elasticQuery.Below is my code snippet.
Sample 2 json store in elastic search
{
"dataLayer":"sourcefeed"
}
{
"dataLayer":"sandbox"
}
BoolQueryBuilder qb = QueryBuilders.boolQuery();
qb.must(QueryBuilders.matchQuery("dataLayer",inputValue);
The input value can be either sourcefeed or sandbox or both,Depending on my input Value it should return the output.For single value it is working fine,But if I give input as InputValue="sourceFeed,sandbox" it is not working.Tried termsQuery also but it is not fetching correctly.Kindly help me to solve the problem.
Thanks Prakash
SearchSourceBuilder query = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
List<QueryBuilder> queryBuilders1 = new ArrayList<QueryBuilder>();
TermsQueryBuilder termsQuery = QueryBuilders.termsQuery("dataLayer.keyword", listOfValues);
queryBuilders1.add(termsQuery);
boolQueryBuilder.must(queryBuilders1.get(0));
query.query(boolQueryBuilder);
add sourceFeed and sandbox etc in one list and pass it in QueryBuilders.termsQuery.
Try this.Hope this will work.

Jest elastic search Query builder query with multiple match strings

I am trying to query elastic search in Java using Jest. I am using a query builder to construct the query.
QueryBuilder matchQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("id", "3434"))
.must(QueryBuilders.matchQuery("name", "name"))
.must(QueryBuilders.matchQuery("action", "login"))
.must(rangeQuery);
//i have this map now
Map<String , String> parameters = new HashMap<>();
parameters.put("id", "3433");
parameters.put("name", "name");
parameters.put("action", "login");
It would be great if some one can tell me if this can be constructed dynamically , like the matchQueries. For instance i would have three match queries , but i would have more. I can put my match query attributes in a Map. But if i iterate that how would we can define this boolQuery ? Anyone has any idea on this ?
Looking for something like this
QueryBuilder matchQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery(map.key, map.value))
.must(rangeQuery);
but how would i contruct this dynamically ?
You can simply iterate over your map and add each condition to the query, like this:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
for(String key : parameters.keySet()){
boolQuery.must(QueryBuilders.matchQuery(key, parameters.get(key)));
}
boolQuery.must(rangeQuery);

Elasticsearch Java API - Bool Query Operator

I am using Elasticsearch 2.4.3 in my Spring Boot App and use following Query
QueryBuilder qb = new BoolQueryBuilder()
.must(QueryBuilders.multiMatchQuery(term, "phoneticFirstName", "phoneticLastName", "phoneticLocationName", "phoneticCompanyName")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND))
.must(QueryBuilders.multiMatchQuery(term, "ngramFirstName^3", "ngramLastName^3", "ngramLocationName^3", "ngramCompanyName^3", "_all")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND));
I want to get a response, where the first Query or the second Query get hits.... can you help me to change that in my Code, please?
UPDATE
"atsCustomPhoneticAnalyzer":{
"type":"custom",
"tokenizer":"whitespace",
"filter":["lowercase","asciifolding","atsPhoneticFilter"]
},
"atsCustomSearchAnalyzer":{
"type":"custom",
"tokenizer":"whitespace",
"filter":["lowercase","asciifolding","umlautStemmer","germanStemmer"]
}
UPDATE #2
QueryBuilder qb = new BoolQueryBuilder()
.should(QueryBuilders.multiMatchQuery(term, "ngramFirstName", "ngramLastName", "ngramLocationName", "ngramCompanyName")
.type(Type.CROSS_FIELDS)
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND)
.boost(3))
.should(QueryBuilders.multiMatchQuery(term, "phoneticLastName")
.analyzer("atsCustomPhoneticAnalyzer")
.operator(Operator.AND))
.should(QueryBuilders.matchQuery(term, "_all")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND))
.minimumNumberShouldMatch(1);
I have 2 indices: persons and activities. When I comment out the second query I get Hits from persons and activities. If all 3 queries are present the hits from activities are not there anymore....
Any ideas?
Simply change must with should instead and add minimumShouldMatch(1)
QueryBuilder qb = new BoolQueryBuilder()
.minimumNumberShouldMatch(1)
.should(QueryBuilders.multiMatchQuery(term, "phoneticFirstName", "phoneticLastName", "phoneticLocationName", "phoneticCompanyName")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND))
.should(QueryBuilders.multiMatchQuery(term, "ngramFirstName^3", "ngramLastName^3", "ngramLocationName^3", "ngramCompanyName^3", "_all")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND));

Elasticsearch multiple condition query using java api

There are multiple documents containing around 100 fields each. I'd like to perform a following search trough elasticsearch Java API 5.x:
There are 3 fields I'd like to use for this search i.e.
department
job
name
I'd like to search the return documents that match fields like "department: D1", "department: D2", "job: J1", "job: J2" "name: N1"
I've been trying to do it this way
String[] departments = ["d1","d2","d3"];
String[] jobs = ["j1","j2","j3"];
String[] names = ["n1"];
MultiSearchRequestBuilder requestbuilder;
requestBuilder.add(client.prepareSearch().setQuery(QueryBuilders.termsQuery("department", departments)));
requestBuilder.add(client.prepareSearch().setQuery(QueryBuilders.termsQuery("job", jobs)));
requestBuilder.add(client.prepareSearch().setQuery(QueryBuilders.termsQuery("name", names)));
MultiSearchResponse response = requestBuilder.get();
However the queries are executed as if each was an individual query, i.e. in this example when j3 exists in d4, the document with d4 will be matched aswell
How to perform the search the way I mentioned? I've been trying numerous different queries and nothing seems to work, is there something I am missing?
You don't want to use MultiSearchRequestBuilder, you simply need to combine your three constraints in a bool/filter query:
BoolQueryBuilder query = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery("department", departments))
.filter(QueryBuilders.termsQuery("job", jobs))
.filter(QueryBuilders.termsQuery("name", names));
SearchResponse resp = client.prepareSearch().setQuery(query).get();
For Elasticsearch 5.6.4 of using HighRestClient, add required number of sourcebuilder...
static RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
public static void multisearch() throws IOException{
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("name", "vijay1"));
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("posts-1","posts-2").source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
RestStatus status = searchResponse.status();
System.out.println(searchResponse.toString());

Categories