Elasticsearch Query: Boosting specific field - elasticsearch

I am using Elasticsearch 2.4.3 and want to boost specific fields in my query. Is this possible? I only see how I can boost an index.
Greetings!
UPDATE
Mapping:
"firstName":{"type":"string",
"analyzer":"customNGram"
},
"lastName":{
"type":"string",
"analyzer":"customNGram"
},
"note":{
"type":"string",
"analyzer":"customNGram"
}
Query (Java API):
QueryBuilder qb = new BoolQueryBuilder()
.must(QueryBuilders.matchQuery("_all", term)
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND));
SearchRequestBuilder searchRequestBuilder = elasticsearchClient.prepareSearch("persons", "activities").setTypes("person", "activity")
.setQuery(qb)
.addHighlightedField("*").setHighlighterRequireFieldMatch(false)
.setHighlighterOrder("score")
.setHighlighterFragmentSize(150)
.setHighlighterForceSource(true)
.setSize(100)
.addIndexBoost("persons", 200)
.setFrom(offset);
return searchRequestBuilder.execute().get();

If you split up your match-query to match individual fields, eg using a multi match query (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html), you can boost the field you like. So something like:
QueryBuilder qb = new BoolQueryBuilder()
.must(QueryBuilders.multiMatchQuery(term, "firstName^3",
"lastName^3", "note")
.analyzer("atsCustomSearchAnalyzer")
.operator(Operator.AND));
should boost firstName and lastName 3 times relative to the note field.

Related

Parent Join in elasticsearch is not searching as expected

We recently migrated from the elastic search version 5.5 to 7.7
The elastic search version 7.7 has removed the concept of the multiple types, so we used the JOIN data type for mapping the relationship between users and tweets like below
https://www.elastic.co/guide/en/elasticsearch/reference/current/parent-join.html
PUT twitter
{
"mappings": {
"properties": {
"my_id": {
"type": "keyword"
},
"my_join_field": {
"type": "join",
"relations": {
"users": "tweets"
}
}
}
}
}
so where the users is the parent and tweets are the children
My twitter index has 1 million entries in the combination of users and tweets,
It works as expected when I use hasParentQuery / hasChildQuery, I get the proper result.
But when I try to query only the parent in the twitter index (i.e) In this case, I want to search only on users in the twitter index, I query like below
// to filter only users
QueryBuilder query1 = QueryBuilders.matchQuery("my_join_field", "users");
// to get all the users whose name starts with joh...
QueryBuilder query2 = QueryBuilders.wildcardQuery("username", "*joh*").boost(1.0f);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(resourceQuery).must(wildcard);
SearchResponse searResp = commondao.prepareSearch("twitter").setQuery(boolQueryBuilder).setFrom(from).setSize(size).execute().actionGet();
the twitter index has 1 million records with 50K entries of users and remaining as tweets.
This query is taking the same time (with / without passing the my_join_field as users) as searching the whole index.
What I am doing wrong? Any help is appreciated!

Elasticsearch How to add bool query inside must_not with multiple match in java API?

I have a query like this in Elasticsearch:
{
"query": {
"bool": {
"must_not": [
{ "match": "filed1" : "value1"},
{ "match": "filed2" : "value2"}
]
}
}
}
I have tried below code.but it only for single match.
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("field1","value1");
What is the way to use must_not with multiple match in java API.Thanks.
Good start! You can simply call mustNot() as many times as conditions you need:
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("field1","value1"));
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("field2","value2"));
Simple as that ;-)
Looks a bit, like the original question was misunderstood. If you have multiple conditions in a single mustNot-constellation, it is not just as easy, as adding multiple .mustNot. Example:
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("name","Donald");
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("hometown","Washington");
If You want to exclude all Donalds from Washington, this is not the right solution, because it will exclude ALL Donalds and ALL from Washington.
If you want to combine these two attributes, just create a new Query (think as if you'd code it with brackets...):
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
BoolQueryBuilder subQuery = QueryBuilders.boolQuery();
subQuery.must(QueryBuilders.matchQuery("name","Donald"); // must (positive!)
subQuery.must(QueryBuilders.matchQuery("hometown","Washington"); // must (positive!)
queryBuilder.mustNot(subQuery); // negate subQuery!

Spring Elasticsearch Aggregation Filtering Not Working

I'm trying to query pricing stats on products I am recording in my Elasticsearch Database by product number. The pricing may be for new, used or refurbished products, so I wish to filter on condition. The condition filter works as a JSON query in Marvel returning stats based on two price documents with condition new.
When I try to do similar using the Java API, I am getting stats based on 4 documents that includes 2 new and 2 refurbished.
Could anyone please identify what I am doing wrong in the Java code below?
Thanks.
Here's the working JSON Query:
GET /stats/price/_search
{
"query": {
"match_phrase": {"mpc": "MGTX2LL/A"}
},
"size": 0,
"aggs" : {
"low_price_stats" : {
"filter": {
"term" : { "condition" : "new"}
},
"aggs" : {
"price_stats" : { "extended_stats" : { "field" : "price" } }
}
}
}
}
And the problematic Java:
public Aggregations aggByManufacturerPartNumber(String mpn) {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("stats")
.withTypes("price")
.withQuery(termQuery("mpn", mpn))
.withFilter(
FilterBuilders.termFilter("condition", "New")
)
.addAggregation(AggregationBuilders.extendedStats("stats_agg").field("price"))
.build();
Aggregations aggregations = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Aggregations>() {
#Override
public Aggregations extract(SearchResponse response) {
return response.getAggregations();
}
});
return aggregations;
}
In your Java code you're only building the price_stats sub-aggregation without its parent filter aggregation. The call to withFilter will create a filter at the query level, not at the aggregation level. The correct Java code that matches your JSON query would be like this:
// build top-level filter aggregation
FilterAggregationBuilder lowPriceStatsAgg = AggregationBuilders.filter("low_price_stats")
.filter(FilterBuilders.termFilter("condition", "new"));
// build extended stats sub-aggregation
lowPriceStatsAgg.subAggregation(AggregationBuilders.extendedStats("stats_agg").field("price"));
// build query
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("stats")
.withTypes("price")
.withQuery(termQuery("mpn", mpn))
.addAggregation(lowPriceStatsAgg)
.build();
// then get the results
Aggregations aggs = response.getAggregations();
Filter lowPriceStats = aggs.get("low_price_stats");
ExtendedStats statsAgg = lowPriceStats.get("stats_agg");
Besides, also note that in your JSON query you have a match_phrase on the mpc field while in your Java code you have a term query on the mpn field. So you probably need to fix that, too, but the above code fixes the aggregation part only.

Retrieve a document from elastic search by matching two fields

My data are stored in elastic search as shown below
{
"identifier":{
"source":"source 1",
"id":"22081070"
},
"title":"Book 1",
"published":2011,
"types":[
"type1",
"type2,
"type3"
]
}
Is there a way to retrieve a document with specific "identifier.id" and "identifier.source" parameters? For example I am retrieving the above document with its id as an input with the following:
QueryBuilder queryBuilder = QueryBuilders.matchQuery("identifier.id", "22081070");
SearchResponse searchResponse = client.prepareSearch("test-index")
.setTypes("type").setQuery(queryBuilder).execute().actionGet();
but I know know how to add the "identifier.source" as a match parameter.
Try this:
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
QueryBuilder queryBuilder1 = QueryBuilders.matchQuery("identifier.id", "22081070");
QueryBuilder queryBuilder2 = QueryBuilders.matchQuery("identifier.source", "source 1");
boolQuery.must(queryBuilder1).must(queryBuilder2);
SearchResponse searchResponse = client.prepareSearch("test-index")
.setTypes("type").setQuery(boolQuery).execute().actionGet();

Build dynamic queries with Spring Data MongoDB Criteria

I would like to run a bulk delete operation on a list of documents in MongoDB that have been selected by the user in the UI so I need to dynamically build a query that looks like the following (the or clause expands for every document selected):
{
$and: [
{
"contentType": "application/vnd.sometype"
},
{
$or: [
{
"metadata.name": "someName",
"metadata.version": "someVersion"
},
{
"metadata.name": "someOtherName",
"metadata.version": "someOtherVersion"
}
]
}
]
},
Fields: null,
Sort: null
Just now I'm using string concatenation to achieve this.
Is it possible to build this query with the Spring Data MongoDB Criteria Builder (org.springframework.data.mongodb.core.query.Criteria)?
Doesn't this work for you?
Criteria criteria = Criteria.where("contentType").is("application/vnd.sometype");
List<Criteria> docCriterias = new ArrayList<Criteria>(docs.size());
for (Document doc: docs) {
docCriterias.add(Criteria.where("metadata.name").is(doc.getName())
.and("metadata.version").is(doc.getVersion()));
}
criteria = criteria.orOperator(docCriterias.toArray(new Criteria[docs.size()]));
?
Here we need to build new query and embed the criteria to the built new query. And also, we have to create a list of criteria using some criteria for embed to the query. Here my example is providing a list of metadata and we don't know the name of parameter which will send for us. So, The solution is as given follow.
List<Criteria> criterias = new ArrayList<>();
for (MetaData metaData : newDoc.getMetaData()) {
Criteria dynamicCriteria = Criteria.where("metaData.key").is(metaData.getKey()).andOperator(Criteria.where("metaData.value").is(metaData.getValue()));
criterias.add(dynamicCriteria);
}
Criteria criteria = new Criteria().andOperator(criterias.toArray(new Criteria[criterias.size()]));
Query searchQuery = new Query(criteria);
List<Document> documents = mongoTemplate.find(searchQuery, Document.class);

Resources