How can i convert DSL query below into c# NEST query?
GET project/_search
{
"size": 0,
"aggs": {
"group_by_projectId": {
"filter": {
"terms": {
"projectId.keyword": ["1", "2", "18"]
}
},
"aggs": {
"project_tags": {
"terms": {
"field": "projectId.keyword",
"size": 100
},
"aggs": {
"last_process_time": {
"max": {
"field": "processedAt"
}
}
}
}
}
}
}
}
would anyone helpy me with the nest query? thank you in advance.
i have converted the query as follows and it works perfectly fine:
_elasticClient.SearchAsync<Project>(s => s
.Size(0)
.Aggregations(a => a
.Filter("filter_by_projectId", f => f
.Filter(ff => ff
.Terms(t => t
.Field(tf => tf.ProjectId)
.Terms(projects
.Select(ps => ps.Id))))
.Aggregations(agg => agg
.Terms("group_by_projectId", st => st
.Field(o => o.ProjectId.Suffix("keyword"))
.Size(100)
.Aggregations(aa => aa
.Max("last_process_time", sa => sa
.Field(o => o.ProcessedAt))))))));
Related
I have a mongodb which looks like this
[
{
"client_id": "abc",
"product_id": "123",
"weight": {
"value": 100
"unit": "kg"
}
},
{
"client_id": "def",
"product_id": "456",
"weight": {
"value": 200
"unit": "kg"
}
}
]
I need to get summation of weight value for a certain client id and product id using mongodb c# client, how can I do that?
I tried this but it is always returning 0
var total_weight = await Collection.AsQueryable()
.Where(
x => x.client_id == "abc" &&
x => x.product_id== "123")
.SumAsync(x => x.weight.value);
Thanks
I think you are looking for this query so you can try this code:
var total_weight = await Collection.AsQueryable<YourModel>()
.Where(x => x.client_id == "abc" && x.product_id == "123")
.GroupBy(x => new { x.client_id, x.product_id })
.Select(x => x.Sum(y => y.weight.value))
.FirstOrDefaultAsync();
I have the following ElasticSearch query:
{
"size": 0,
"aggs": {
"product_attribute_nested_agg": {
"nested": {
"path": "productAttributes"
},
"aggs": {
"inner": {
"filter": {
"fuzzy": {
"productAttributes.name": {
"value": "SS",
"fuzziness": 3
}
}
},
"aggs": {
"terms_nested_agg": {
"terms": {
"field": "productAttributes.name"
}
}
}
}
}
}
}
}
I am using Nest as client library and here how I generate nested aggregation query using Fluent DSL:
var searchResponse = elasticClient.Search<ProductType>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType)))
.Size(0)
.Aggregations(a => a
.Nested("product_attribute_nested_agg", n => n
.Path(Infer.Field<ProductType>(ff => ff.ProductAttributes))
.Aggregations(aa => aa
.Terms("terms_nested_agg", t => t
.Field(p => p.ProductAttributes.Suffix("name"))
)
)
)
)
);
But how can I generate the inner filter using Fluent DSL syntax?
After some investigation and searching, I was able to generate filtered nested aggregation using Nest fluent DSL:
var searchResponse = elasticClient.Search<ProductType>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType)))
.Size(0)
.Aggregations(a => a
.Nested("product_attribute_nested_agg", n => n
.Path(Infer.Field<ProductType>(ff => ff.ProductAttributes))
.Aggregations(a1 => a1
.Filter("inner", ia => ia
.Filter(f => f
.Fuzzy(fuzzy => fuzzy
.Field(Infer.Field<ProductType>(ff => ff.ProductAttributes.First().Name))
.Value(productAttribute)
.Fuzziness(Fuzziness.EditDistance(3))
)
).Aggregations(na => na
.Terms("terms_nested_agg", t => t
.Field(p => p.ProductAttributes.Suffix("name"))
)
)
)
)
)
)
);
var result = new List<ProductAttributesSuggestionResult>();
var nestedAgg = searchResponse.Aggregations.Nested("product_attribute_nested_agg");
var inner = (SingleBucketAggregate)nestedAgg.Values.FirstOrDefault();
var termsAgg = inner.Terms("terms_nested_agg");
foreach (var bucket in termsAgg.Buckets)
{
result.Add(new ProductAttributesSuggestionResult
{
Name = bucket.Key,
ProductsCount = bucket.DocCount ?? 0
});
}
I hope my answer helping others having the same issue.
I have this pure call to Elastic that works. It returns 29 docs:
GET /idxsearch-test/movies/_search
{
"size": 20,
"query": {
"bool": {
"must": {
"bool" : {
"should": [
{"term": {"tag.name": "Paris"}},
{"multi_match" : {
"operator": "and",
"query" : "Paris",
"fields": ["movie_title.default^10",
"movie_title.snowball^2",
"movie_title.shingles^2",
"movie_title.ngrams"]}}
]
}
},
"filter": {
"term": { "is_adult": false }
}
}
},
"_source": ["id_content", "movie_title", "vote_average", "tag.name", "is_adult"]
}
I need to use Nest, so I converted to this. It returns 0:
var vod = client.Search<dynamic>(s => s
.Size(10)
.From(1)
.Index(defaultIndex)
.Type("movies")
.Query(qry1 => qry1
.FunctionScore(fs =>
fs.Query(qry2 =>
qry2.Bool(bool1 =>
bool1.Must(must1 =>
must1.Bool(bool2 =>
bool2.Should(should1 =>
{
QueryContainer qc = null;
qc &= should1.Term(tt => tt.Field("tag.name").Value(keywords));
qc &= should1.MultiMatch(mm1 => mm1.Fields(ff => ff
.Field("movie_title.default^10")
.Field("movie_title.snowball^2")
.Field("movie_title.shingles^2")
.Field("movie_title.ngrams"))
.Operator(Operator.And)
.Query(keywords));
return qc;
})
)
)
.Filter(fil =>
{
QueryContainer query = null;
if (!includeAdult)
query &= fil.Terms(fil2 => fil2.Field("is_adult").Terms(false));
return query;
})
)
)
.BoostMode(FunctionBoostMode.Sum)
.Functions(ff => ff.FieldValueFactor(fv => fv.Field("vote_average")
.Factor(0.5)
.Modifier(FieldValueFactorModifier.Log1P)))
))
);
But the results are different... What am I missing?
Is there a way to make the same call in a cleaner and correct way?
cheers
The first query can be written as
//Fluent
client.Search<dynamic>(
s => s.
Index("idxsearch-test").
Type("movies").
Take(20).
Query(q => q.Bool(
b => b.Must(m => m.Term(t => t.Field("tag.name").Value("Paris")) ||
m.MultiMatch(mm => mm.Fields(f => f.
Field("movie_title.default", 10).
Field("movie_title.snowball", 2).
Field("movie_title.shingles", 2).
Field("movie_title.ngrams")))).
Filter(f => includeAdult ? f.Term(t => t.Field("is_adult").Value("")) : null))).
Source(sc => sc.Includes(i => i.Field("id_content").Field("movie_title").Field("vote_average").Field("tag.name").Field("is_adult"))));
//Object
client.Search<dynamic>(new SearchRequest<dynamic>("idxsearch-test", "movies")
{
Size = 20,
Query = new BoolQuery
{
Must = new QueryContainer[]
{
new BoolQuery
{
Should = new QueryContainer[]
{
new TermQuery() { Field = "tag.name", Value = "Paris" },
new MultiMatchQuery
{
Fields = new [] { "movie_title.default^10", "movie_title.snowball^2", "movie_title.shingles^2", "movie_title.ngrams" }
}
}
}
},
Filter = includeAdult ? new QueryContainer[]
{
new TermQuery { Field = "is_adult", Value = false }
} : null
},
Source = new Union<bool, ISourceFilter>(new SourceFilter { Includes = new[] { "id_content", "movie_title", "vote_average", "tag.name", "is_adult" } })
});
Alright, so the query works perfectly in Sense in Chrome. I use the following query:
{
"size":127,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"prefix": {
"name": {
"value": "incomp"
}
}
},
{
"match": {
"name": "a word that is"
}
}
]
}
},
"functions": [
{
"exp": {
"date": {
"origin": "now/d",
"scale": "3w",
"offset": "10d",
"decay": "0.88"
}
}
}
]
}
}
}
In short, I match on the indexed "name" property of a custom type in ES, giving priority to recently added items and supporting "suggestions as you type" - thus the prefix query. It works perfectly well, tuned as it is, so my next step would be to reproduce in NEST.
However, I'm facing some issues with the .NET NEST code below:
var results4 = _client.Search<customDataType>(
s => s.Size(5030)
.Query(q => q
.FunctionScore(fs => fs
.Name("another_named_query")
.BoostMode(FunctionBoostMode.Multiply)
.ScoreMode(FunctionScoreMode.Multiply)
.Query(qu => qu
.Bool(b => b
.Must(m => m
.Prefix(p => p
.Field(ff => ff.Name)
.Value(prefixVal)))
.Must(m2 => m2
.Match(mh => mh
.Field(f2 => f2.Name)
.Query(stringBeforePrefixVal)))))
/*.Functions( fcs => fcs.ExponentialDate(
exp => exp
.Origin(DateMath.Now)
.Scale(new Time(1814400000))
.Offset(new Time(864000000))
.Decay(0.88d))
)*/)));
I can't figure out why any attempt to use the "FunctionScore" method results in what a MatchAll() would do - all records are returned.
Meanwhile, when adding the Functions (commented above) I get an UnexpectedElasticsearchClientException with a NullReference inner exception at Nest.FieldResolver.Resolve(Field field) in C:\code\elasticsearch-net\src\Nest\CommonAbstractions\Infer\Field\FieldResolver.cs:line 31.
I'm baffled by all of this, and there don't seem to be similar problems that I can use as a starting point. Is there anything I can do to get the query above running, or should I resort to manually doing a restful API call?
Almost correct, but you're missing the field on which the exponential date decay function should run. Assuming your POCO looks like
public class customDataType
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
the query would be
var prefixVal = "incomp";
var stringBeforePrefixVal = "a word that is";
var results4 = client.Search<customDataType>(s => s
.Size(5030)
.Query(q => q
.FunctionScore(fs => fs
.Name("another_named_query")
.BoostMode(FunctionBoostMode.Multiply)
.ScoreMode(FunctionScoreMode.Multiply)
.Query(qu => qu
.Bool(b => b
.Must(m => m
.Prefix(p => p
.Field(ff => ff.Name)
.Value(prefixVal)))
.Must(m2 => m2
.Match(mh => mh
.Field(f2 => f2.Name)
.Query(stringBeforePrefixVal)))))
.Functions(fcs => fcs
.ExponentialDate(exp => exp
.Field(f => f.Date)
.Origin("now/d")
.Scale("3w")
.Offset("10d")
.Decay(0.88)
)
)
)
)
);
which yields
{
"size": 5030,
"query": {
"function_score": {
"_name": "another_named_query",
"query": {
"bool": {
"must": [
{
"match": {
"name": {
"query": "a word that is"
}
}
}
]
}
},
"functions": [
{
"exp": {
"date": {
"origin": "now/d",
"scale": "3w",
"offset": "10d",
"decay": 0.88
}
}
}
],
"score_mode": "multiply",
"boost_mode": "multiply"
}
}
}
You can take advantage of operator overloading in NEST to shorten the bool query further, by &&ing the prefix and match query
var results4 = client.Search<customDataType>(s => s
.Size(5030)
.Query(q => q
.FunctionScore(fs => fs
.Name("another_named_query")
.BoostMode(FunctionBoostMode.Multiply)
.ScoreMode(FunctionScoreMode.Multiply)
.Query(qu => qu
.Prefix(p => p
.Field(ff => ff.Name)
.Value(prefixVal)
) && qu
.Match(mh => mh
.Field(f2 => f2.Name)
.Query(stringBeforePrefixVal)
)
)
.Functions(fcs => fcs
.ExponentialDate(exp => exp
.Field(f => f.Date)
.Origin("now/d")
.Scale("3w")
.Offset("10d")
.Decay(0.88)
)
)
)
)
);
I have to search for a keyword on multiple fields for the same query string.
"bool": {
"should": [
{
"match": {
"ABC": "Apple"
}
},
{
"match": {
"XYZ": "Apple"
}
}
]
}
When I wrote the query DSL , it has been translated as multimatch query(Not sure if the above code and DSL are same)
.Bool(b => b
.Should(sh => sh
.MultiMatch(c => c
.Fields(f => f.Field(p => p.ABC).Field("XYZ"))
.Query(keyz)))))
Similarly i want to write a DSL query but i want to do match_phrase operation. Can some one help me in solving this.
TIA
Given a document type
public class Document
{
public string ABC { get; set; }
public string XYZ { get; set; }
}
This would be
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex)
.DefaultFieldNameInferrer(p => p);
var client = new ElasticClient(connectionSettings);
var keyz = "Apple";
client.Search<Document>(s => s
.Query(q => q
.Bool(b => b
.Should(sh => sh
.Match(c => c
.Field(p => p.ABC)
.Query(keyz)
),
sh => sh
.Match(c => c
.Field(p => p.XYZ)
.Query(keyz)
)
)
)
)
);
You can shorten this by taking advantage of operator overloading
client.Search<Document>(s => s
.Query(q => q
.Match(c => c
.Field(p => p.ABC)
.Query(keyz)
)
|| q.Match(c => c
.Field(p => p.XYZ)
.Query(keyz)
)
)
);
Both produce
{
"query": {
"bool": {
"should": [
{
"match": {
"ABC": {
"query": "Apple"
}
}
},
{
"match": {
"XYZ": {
"query": "Apple"
}
}
}
]
}
}
}