How to write multi key push in spring data mongodb? - spring

I've the following aggregation query in mongodb:
{"$group": {"_id": "$code", "statusCount": {"$push": {"status": "$status", "count":"$total" }}}}
How can I write the $push part in spring data mongodb?

I've found how to do this. Hope it'll help others also:
DBObject dbObject = new BasicDBObject();
dbObject.put("status", "$status");
dbObject.put("total", "$total");
Aggregation agg = newAggregation(
group("code").push(dbObject).as("statusCount")
);

Related

How can I make phrase suggester query with Elasticsearch java api?

I am using 7.10. version of elasticsearch. I created an index and did settings-mappings. Then I sent query to index by using http requests. I got the results I need, but I want to do same thing with Java API. However, I couldn't.
Can you help me to send request and get the result as list in java from scratch ?
And here it is my query that I used for obtain suggestions:
{
"suggest": {
"text": "some title I want to search",
"phrase_suggester": {
"phrase": {
"field": "title.shingle",
"max_errors": 2,
"size": 5,
"confidence": 0.0,
"direct_generator": [{
"field": "title.shingle",
"max_edits": 2
}
]
}
}
}
}
How can I write this query with Elasticsearch Java API. Can you help me figure this out ?
This would be the way to build the request:
client.search(searchRequestBuilder -> searchRequestBuilder
.suggest(suggestBuilder -> suggestBuilder
.text("some title I want to search")
.suggesters("phrase_suggester", fieldSuggesterBuilder -> fieldSuggesterBuilder
.phrase(phraseBuilder -> phraseBuilder.field("title.shingle")
.maxErrors(2d)
.size(5)
.confidence(0.0)
.directGenerator(directGeneratorBuilder -> directGeneratorBuilder
.field("title.shingle")
.maxEdits(2))))),
YourEntity.class);
Btw, the new client was in 7.16, you wrote 7.14?
Finaly I've found my own answers. It was so hard to find the solution due to lack of documents about these kind of specific topics. I'm sharing my solution for those who wondered:
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
PhraseSuggestionBuilder builder = SuggestBuilders.phraseSuggestion("title.shingle")
.addCandidateGenerator(new DirectCandidateGeneratorBuilder("title.shingle")
.suggestMode("always"))
.text(query)
.maxErrors(2f)
.confidence(0f);
SuggestBuilder suggestBuilder = new SuggestBuilder().addSuggestion("suggestion", builder);
searchSourceBuilder.suggest(suggestBuilder);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("index_name");
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

Spring mongodb - group operation after unwind - can not find $first or $push

I have articles & tags collection. Articles contain tags which is array of objectId. I want to fetch tagName as well, so I unwind (this gives me multiple rows - 1 per tag array entry) => lookup (joins with tabs collection) => group (combine it into original result set)
My mongodb query is as follows, which gives me correct result:
db.articles.aggregate([
{"$unwind": "$tags"},
{
"$lookup": {
"localField": "tags",
"from": "tags",
"foreignField": "_id",
"as": "materialTags"
}
},
{
"$group": {
"_id": "$_id",
"title": {"$first": "$title"},
"materialTags": {"$push": "$materialTags"}
}
}
])
My corresponding Spring code:
UnwindOperation unwindOperation = Aggregation.unwind("tags");
LookupOperation lookupOperation1 = LookupOperation.newLookup()
.from("tags")
.localField("tags")
.foreignField("_id")
.as("materialTags");
//I also want to add group operation but unable to find the proper syntax ??.
Aggregation aggregation = Aggregation.newAggregation(unwindOperation,
lookupOperation1, ??groupOperation?? );
AggregationResults<Article> resultList
= mongoTemplate.aggregate(aggregation, "articles", Article.class);
I tried to play around with group operation but without much luck. How can I add group operations as per original query ?
Thanks in advance.
Group query syntax in Spring for
{
"$group": {
"_id": "$_id",
"title": {"$first": "$title"},
"materialTags": {"$push": "$materialTags"}
}
}
is
Aggregation.group("_id").first("title").as("title").push("materialTags").as("materialTags")
Final query
UnwindOperation unwindOperation = Aggregation.unwind("tags");
LookupOperation lookupOperation1 = LookupOperation.newLookup()
.from("tags")
.localField("tags")
.foreignField("_id")
.as("materialTags");
Aggregation aggregation = Aggregation.newAggregation(unwindOperation,
lookupOperation1, Aggregation.group("_id").first("title").as("title").push("materialTags").as("materialTags") );
AggregationResults<Article> resultList
= mongoTemplate.aggregate(aggregation, "articles", Article.class);
To get more info please go thru the below references
http://www.baeldung.com/spring-data-mongodb-projections-aggregations
spring data mongodb group by
Create Spring Data Aggregation from MongoDb aggregation query
https://www.javacodegeeks.com/2016/04/data-aggregation-spring-data-mongodb-spring-boot.html

Post Filter Query in Elasticsearch 2.3.3 using Java

I have built a web app on top of elasticsearch (v2.3.3). To filter the query, I am using post filter of elasticsearch. But I came to know that, if I use post filter then the performance benefit of filtering will be lost since I am not using any aggregation or differential filtering. (Reference: https://www.elastic.co/guide/en/elasticsearch/guide/current/_post_filter.html)
This is how my elasticsearch client looks like:
Client client = TransportClient.builder().build().addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),
9300));
SearchResponse response = client.prepareSearch("index_name")
.setTypes("index_type")
.setQuery(QueryBuilders.simpleQueryStringQuery(query)
.field("newContent").field("T"))
.setPostFilter(QueryBuilders.termQuery(Collection, true))
.setFetchSource(new String[] { "U", "UE", "UD", "T" }, null)
.setVersion(true).addHighlightedField("newContent").setFrom(0)
.setSize(10).execute().actionGet();
I have also read that filtered query is depreciated in elasticsearch 2.x versions. Is there any other way which will help me to apply a filter before the query is executed? I might be missing something obvious. I would appreciate your help.
You simply need to bring the filter present in post filter inside a bool/filter query. Try to do hits instead:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.simpleQueryStringQuery(query)
.field("newContent").field("T"))
.filter(QueryBuilders.termQuery(Collection, true));
SearchResponse response = client.prepareSearch("index_name")
.setTypes("index_type")
.setQuery(boolQuery)
.setFetchSource(new String[] { "U", "UE", "UD", "T" }, null)
.setVersion(true).addHighlightedField("newContent").setFrom(0)
.setSize(10).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);

How to rewrite ElasticSearch DSL query with the Java API

I have got a working query for ElasticSearch, but I have problems to execute the same query with the Java API of ElasticSearch.
How can I express the query below with the Java API of ElasticSearch?
---
size: 0
query:
match_all: []
facets:
age:
statistical:
field : timestamp
It should be something like:
client.prepareSearch("yourindex")
.setTypes("yourtype")
.setQuery(QueryBuilders.matchAllQuery())
.addFacet(FacetBuilders.statisticalFacet("age").field("timestamp"))
.setSize(0)
.execute()
.actionGet();
You can convert your query DSL to a JSON string, and then wrap it with QueryBuilders.wrapperQuery() or WrapperQueryBuilder(), finally do the query with Java API like this.
SearchResponse response = client.prepareSearch("yourIndex")
.setTypes("yourType")
.setQuery(dslQB)
.setFrom(currentItem)
.setSize(pageSize)
.execute()
.actionGet();
`

Resources