I want to find a list of models matched either field nameEnglish or nameChinese by a keyword. I spent more than an hour googling but I cannot do it. Please help.
Springboot Mongo starter example https://spring.io/guides/gs/accessing-data-mongodb/
The custom query I want to execute and return a list result
db.mymodel.aggregate([
{
$match: {
$or :[
{ nameChinese: /門/ },
{ nameEnglish: /cocina/i }
]
}
},
{ $sort: {nameEnglish: 1} }
])
My best trial so far
interface MyModelRepository : MongoRepository<MyModel, String> {
#Query(value = "{ '\$match': { \$or: [ {'nameEnglish': { \$regex: ?0 } }, {'nameChinese': { \$regex: ?0 } } ] }")
fun findByMyQuery(name: String): List<MyModel>
}
For the regex, I also want it to be case insensitive.
I found the answer after a hot water shower ( and one day of googling and reading documents). Hope this help someone in the future.
#Query(value = "{ \$or: [ {'nameEnglish': { \$regex: ?0, \$options: 'i'}}, {'nameChinese': { \$regex: ?0 }}] }", sort = "{nameEnglish: 1}")
Related
I'm new to stackoverflow
here is my problem
I want to make a request in ES that in first perform a must then a filter. In sql it should lookalike to this below
SELECT * FROM table WHERE name = "the_name" AND type IN ("type1", "type2")
Here is my implementation of this case
#Override
public List<Example> findByName(String pattern, String... types) {
// Prepare query
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("name", pattern))
.filter(QueryBuilders.termsQuery("type", types));
// Execute query
return new ArrayList<>(this.elasticsearchQuery.findAgainstFields(Example.class, queryBuilder));
}
Next, my implementation for method findAgainstFields
#SuppressWarnings("unchecked")
#Override
public <T> List<T> findAgainstFields(Class<?> t, QueryBuilder query) {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder
.withIndices("my_indice")
.withTypes(t.getSimpleName())
.withSort(new ScoreSortBuilder().order(SortOrder.DESC))
.withQuery(query)
.withPageable(PageRequest.of(0, 5)).build();
// Execute query
return (List<T>) this.elasticsearchTemplate.queryForList(nativeSearchQuery, t);
}
And when I run the project this method (findByName) return an empty array. However, when I remove the .filter(QueryBuilders.termsQuery("type", types)) i got a result. So, on which part i'm wrong?
Thanks in advance
ps: I use ES 5.5 and Java 8 oracle
UPDATE
ES query is this:
{
"bool" : {
"must" : [
{
"term" : {
"name" : {
"value" : "eso",
"boost" : 1.0
}
}
}
],
"filter" : [
{
"terms" : {
"type" : [
"Society",
"Institut"
],
"boost" : 1.0
}
}
],
"disable_coord" : false,
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
So here, i try to find the data with name as eso with type who can be Society or Institut
the problem was in the mapping file not on java source code.
so i updated the file by changing the type of the property type to keyword (it was text before) and everything works fine.
I have a ElasticSearch Query that is working well (curl), is my first Query,
First I am filtering by Organization (Multitenancy), then group by Customer, Finally sum the amount of the sales but I only want to have the 3 best customers.
My question is.. How to build the aggregation with the AggregationBuilders to get "bucket_sort" statement. I got the sales grouping by customer with Java API.
Elastic Query is:
curl -X POST 'http://localhost:9200/sales/sale/_search?pretty' -H 'Content-Type: application/json' -d '
{
"aggs": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"term": {
"organization_id": "15"
}
}
]
}
},
"aggs": {
"by_customer": {
"terms": {
"field": "customer_id"
},
"aggs": {
"sum_total" : {
"sum": {
"field": "amount"
}
},
"total_total_sort": {
"bucket_sort": {
"sort": [
{"sum_total": {"order": "desc"}}
],
"size": 3
}
}
}
}
}
}
}
}'
My Java Code:
#Test
public void queryBestCustomers() throws UnknownHostException {
Client client = Query.client();
AggregationBuilder sum = AggregationBuilders.sum("sum_total").field("amount");
AggregationBuilder groupBy = AggregationBuilders.terms("by_customer").field("customer_id").subAggregation(sum);
AggregationBuilder aggregation =
AggregationBuilders
.filters("filtered",
new FiltersAggregator.KeyedFilter("must", QueryBuilders.termQuery("organization_id", "15"))).subAggregation(groupBy);
SearchRequestBuilder requestBuilder = client.prepareSearch("sales")
.setTypes("sale")
.addAggregation(aggregation);
SearchResponse response = requestBuilder.execute().actionGet();
}
I hope I got your question right.
Try adding "order" to your groupBy agg:
AggregationBuilder groupBy = AggregationBuilders.terms("by_customer").field("customer_id").subAggregation(sum).order(Terms.Order.aggregation("sum_total", false));
One more thing, if you want the top 3 clients than your .size(3) should be set on groupBy agg as well and not on sorting. like that:
AggregationBuilder groupBy = AggregationBuilders.terms("by_customer").field("customer_id").subAggregation(sum).order(Terms.Order.aggregation("sum_total", false)).size(3);
As another answer mentioned, "order" does work for your use case.
However there are other use cases where one may want to use bucket_sort. For example if someone wanted to page through the aggregation buckets.
As bucket_sort is a pipeline aggregation you cannot use the AggregationBuilders to instantiate it. Instead you'll need to use the PipelineAggregatorBuilders.
You can read more information about the bucket sort/pipeline aggregation here.
The ".from(50)" in the following code is an example of how you can page through the buckets. This causes the items in the bucket to start from item 50 if applicable. Not including "from" is the equivalent of ".from(0)"
BucketSortPipelineAggregationBuilder paging = PipelineAggregatorBuilders.bucketSort(
"paging", List.of(new FieldSortBuilder("sum_total").order(SortOrder.DESC))).from(50).size(10);
AggregationBuilders.terms("by_customer").field("customer_id").subAggregation(sum).subAggregation(paging);
Now I got a problem as I need to query some data from a type(or index) named 'product', and I have three parameters( $p1, $p2, $p3) which can determine some catagories,then I need get all the product in those catagories.
I know how it can be done in MySQL like this:
select *
from product
where catagory in (
select catagory
from product
where p1 = $p1 and p2=$p2 and p3=$p3
)
And I know I can do this in solr like
{!join from=catagory to=catagory}p1:$p1 AND p2:$p2 AND p3:$p3
But I want to know how can I do this in ElasticSearch.
BTW,sorry for my pool English. I do appreciate for your help.
after I look through official docs, this can be resolved like this:
1. create your index with a join type
put /product
{
"mappings":{
"cata" : {
"properties" : {
"join_field": {
"type": "join",
"relations": {
"header": "line"
}
}
}
}
}
}
create a header data
post /product
{
"p1":"1",
"p2":"2",
"p3":"3",
"join_field":"header"
}
return with "_id:"xxx"
create a line data
post /cata?routing=xxx (! routing must be header's '_id',so is 'parent' below)
{
"p1":"1",
"p2":"1",
"p3":"1",
"other":"others...",
"join_field":{
"name": "line",
"parent": "xxx"
}
}
4. query data
post /cata/_search
{
"query": {
"has_parent" : {
"parent_type" : "header",
"query" : {
"has_child" : {
"type" : "line",
"query" : {
"term" : {
"other" : "others..."
}
}
}
}
}
}
}
the way above fix my problem
db.collection.aggregate([
{$match : { name : "name" } },
{$project: {
name: 1,
sent: {
$size: {
"$ifNull": [ "$audience", [] ]
}
}
}
}]);
How can I do the above mongo aggregation with Spring data?
I know this is an old post and you might have found the answer, but, just for the sake of others, I'm posting it here.
Aggregation aggregation = Aggregation.newAggregation(
.match(Criteria.where("name").is("name"))
.project("name")
.and(ArrayOperators.Size.lengthOfArray(ConditionalOperators.ifNull("audience").then(Collections.emptyList()))).as("sent")
);
I have an aggregation command in script console as below,
> db.examSessionCol.aggregate( [ { $group : { _id : "$examinationId", avgScore: {$avg: "$score"}, co
unt: { $sum: 1 } } } ] )
Here is the result,
{ "_id" : NumberLong(4), "avgScore" : 81.4, "count" : 5 }
{ "_id" : NumberLong(1), "avgScore" : 17.2, "count" : 40 }
I need to apply it into my java based project, I found there is little documents about usage of aggregation in MongoTemplate, could anyone help me how I can write the related java code with good performance?
Following is the return object:
public class ExamParticipatedItem {
protected int examinationId;
protected int count;
protected double avgScore;
}
And the method written by me but doesn't work currently,
public List<ExamParticipatedItem> getExamParticipatedItems() {
return mongoTemplate.aggregate(Aggregation.newAggregation(ExaminationSession.class, GroupOperationBuilde), ExamParticipatedItem.class, collectionName).getMappedResults();//it's not completed
}
Thanks in advance.
The right answer for this project and solution is from this document:
Aggregation aggregation = newAggregation(ExaminationSession.class,
group("examinationId").first("examinationId").as("examinationId").avg("score").as("avgScore").count().as("count"));
List<ExamParticipatedItem> aggregationresults = mongoTemplate.aggregate(aggregation, collectionName, ExamParticipatedItem.class)
.getMappedResults();