having a problem with my elasticsearch.
Setup: Having a Company-Class with the data field "companyName".
My search shall search and response all companys with the searched term.
If I try to sort via
.Sort(x=> x.OnField(x => x.CompanyName).Descending())
The data aren't sorted rightly - reference stackOverflow
I tried the given solution, but if I set my companyName to "not_analyzed" I cant even search anymore for the comnpany name or like a beginning "goo" (google)
So I tried to set up a multifield mapping, with a suffix, which isn't analyzed and one which is analyzed.
My Index is set up like:
client.CreateIndex(IndexName, c => c
.AddMapping<Exhibitor>(m =>m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf=>mf
.Name(x=>x.CompanyName)
.Fields(fs => fs
.String(s=>s.Name(t=>t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s=>s.Name(t=>t.CompanyName.Suffix("raw")).Index(FieldIndexOption.NotAnalyzed))))
)
)
)
);
My search looks like:
string SearchTerm ="my search term"
results = GetClient().Search<Company>(s => s
.Query(qa => qa
.MatchPhrasePrefix(m => m
.OnField(f=>f.CompanyName)
.Query(SearchTerm)
))
.Sort(x => x.OnField(x => x.CompanyName.Suffix("raw")).Descending())
.Size(maxResults).Skip(page * pageSize).Take(pageSize)
);
But that still doesn't work.
Any ideas?
Thanks in advance.
Update 1:
For case insensitive sorting I added an custom analyzer:
var companyAnalyzer = new CustomAnalyzer
{
Filter = new List<string> { "standard", "lowercase" },
Tokenizer = "keyword"
};
client.CreateIndex(IndexName, c => c
.Analysis(analysis => analysis
.Analyzers(a => a
.Add("companyanalyzer", companyAnalyzer)
)
)
.AddMapping<Exhibitor>(m => m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf => mf
.Name(x => x.CompanyName)
.Fields(fs => fs
.String(s => s.Name(t => t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s => s.Name(t => t.CompanyName.Suffix("raw")).Index(FieldIndexOption.Analyzed).Analyzer("companyanalyzer"))))
)
)
);
This example is working, maybe it will put some light on your issue.
var indicesResponse = client.DeleteIndex(descriptor => descriptor.Index(indexName));
client.CreateIndex(indexName, c => c
.AddMapping<Exhibitor>(m => m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf => mf
.Name(x => x.CompanyName)
.Fields(fs => fs
.String(s => s.Name(t => t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s => s.Name(t => t.CompanyName.Suffix("raw")).Index(FieldIndexOption.NotAnalyzed))))
)));
client.Index(new Exhibitor { Id = 1, CompanyName = "a test" });
client.Index(new Exhibitor { Id = 2, CompanyName = "b test" });
client.Index(new Exhibitor { Id = 3, CompanyName = "c test" });
client.Refresh();
string SearchTerm = "test";
var results = client.Search<Exhibitor>(s => s
.Query(qa => qa
.MatchPhrasePrefix(m => m
.OnField(f => f.CompanyName)
.Query(SearchTerm)
))
.Sort(x => x.OnField(f => f.CompanyName.Suffix("raw")).Descending())
);
Result of this query:
{
"took": 2,
"timed_out": false,
"_shards": {..}
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "3",
"_score": null,
"_source": {
"id": 3,
"companyName": "c test"
},
"sort": [
"c test"
]
},
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "2",
"_score": null,
"_source": {
"id": 2,
"companyName": "b test"
},
"sort": [
"b test"
]
},
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "1",
"_score": null,
"_source": {
"id": 1,
"companyName": "a test"
},
"sort": [
"a test"
]
}
]
}
}
Index mapping:
{
"my_index" : {
"mappings" : {
"exhibitor" : {
"properties" : {
"companyName" : {
"type" : "string",
"analyzer" : "standard",
"fields" : {
"raw" : {
"type" : "string",
"index" : "not_analyzed"
}
}
},
"id" : {
"type" : "integer"
}
}
}
}
}
}
Hope it helps.
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 this DSL query which return result in ElasticSearch console.
GET /person/_search
{
"query": {
"bool": {
"must": [
{
"query_string": {
"fields": [
"nameDetails.name.nameValue.firstName",
"nameDetails.name.nameValue.surname",
"nameDetails.name.nameValue.middleName"
],
"query": "Pibba Fawsu~"
}
}
]
}
}
}
The result is below:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 10.335077,
"hits" : [
{
"_index" : "person",
"_type" : "_doc",
"_id" : "70002",
"_score" : 10.335077,
"_source" : {
"gender" : "Male",
"nameDetails" : {
"name" : [
{
"nameValue" : {
"firstName" : "Fawsu",
"middleName" : "L.",
"surname" : "Pibba"
},
"nameType" : "Primary Name"
},
{
"nameValue" : {
"firstName" : "Fausu",
"middleName" : "L.",
"surname" : "Pibba"
},
"nameType" : "Spelling Variation"
}
]
}
}
}
]
}
}
But when I convert the query to NEST C#, it return no result.
var response = await _elasticClient.SearchAsync<Person>(s => s
.Index("person")
.Query(q => q
.Bool(b => b
.Must(
mu => mu
.QueryString(m => m
.Fields(f => f.Field(f => f.NameDetails.Name[0].NameValue.FirstName))
.Fields(f => f.Field(f => f.NameDetails.Name[0].NameValue.Surname))
.Fields(f => f.Field(f => f.NameDetails.Name[0].NameValue.MiddleName))
.Query("Pibba Fawsu")
)
)
)
)
);
But when I test it with just FirstName like below, it returns result.
var response = await _elasticClient.SearchAsync<Person>(s => s
.Index("person")
.Query(q => q
.Bool(b => b
.Must(
mu => mu
.QueryString(m => m
.Fields(f => f.Field(f => f.NameDetails.Name[0].NameValue.FirstName))
.Query("Pibba Fawsu")
)
)
)
)
);
Query string query returns documents based on a provided query string, using a parser with a strict syntax. Your first NEST c# code emphasize match all field, but no result. So you should add MinimumShouldMatch restriction.
You can add should condition on firstName, surName, middleName. Even if one name had been matched, it would like to return.
client.Search<Document>(s => s
.Query(q => q
.Bool(b => b
.Should(sh => sh
.Match(c => c
.Field(p => p.firstName)
.Query(keyz)
),
sh => sh
.Match(c => c
.Field(p => p.middleName)
.Query(keyz)
),
sh => sh
.Match(c => c
.Field(p => p.surName)
.Query(keyz)
)
)
)
)
);
You problem is the Fields error used. The .Fields().Fields().Fields() only use the last Field MiddleName , so no response.
change you C# Nest code:
var response = await client.SearchAsync<Person>(s => s.Index("person")
.Query(q => q
.Bool(b => b
.Must(
mu => mu
.QueryString(m => m
.Fields(f => f.Fields(f => f.NameDetails.Name[0].NameValue.FirstName, f => f.NameDetails.Name[0].NameValue.Surname, f => f.NameDetails.Name[0].NameValue.MiddleName))
.Query("Pibba Fawsu")
)
)
)
)
);
My code is as below
GetDairyHeaderInfoByEmail(id)
.Where(p => p.ATTRIBUTE15 == id)
.Select(jk=> new {
jk.HEADER_ID_PK,
jk.VENDOR_ID,
jk.VENDOR_SITE_ID,
jk.VENDOR_NAME,
jk.ADDRESS_LINE1,
jk.ATTRIBUTE15
})
.GroupBy(p => p.HEADER_ID_PK)
.Select(p => new {
header_id_pk = p.Key,
invoice_id_pk = _ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(k => k.HEADER_ID_PK == p.Key).Select(c => new { c.APP_INVOICES_ID_PK, c.INVOICE_TYPES, c.IS_HOURLY }).ToList() }).ToList();
The results I see is as below
[ {
"header_id_pk": 800.0,
"invoice_id_pk": [
{
"APP_INVOICES_ID_PK": 1058.0,
"INVOICE_TYPES": "EPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1059.0,
"INVOICE_TYPES": "CPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1060.0,
"INVOICE_TYPES": "WHT ON DIVIDEND",
"IS_HOURLY": "N"
},
{
"APP_INVOICES_ID_PK": 1061.0,
"INVOICE_TYPES": "L.P",
"IS_HOURLY": "N"
}
] } ]
But I want the results as below
[ {
"header_id_pk": 800.0,
"HEADER_ID_PK" : 800.0,
"VENDOR_ID" : 12.0,
"VENDOR_SITE_ID" : 33.0,
"VENDOR_NAME" : Faisal,
"ADDRESS_LINE1" : XYZ address,
"invoice_id_pk": [
{
"APP_INVOICES_ID_PK": 1058.0,
"INVOICE_TYPES": "EPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1059.0,
"INVOICE_TYPES": "CPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1060.0,
"INVOICE_TYPES": "WHT ON DIVIDEND",
"IS_HOURLY": "N"
},
{
"APP_INVOICES_ID_PK": 1061.0,
"INVOICE_TYPES": "L.P",
"IS_HOURLY": "N"
}
] } ]
Sorry about the mess if any, this is my first question.
Thanks
var dairy = _ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(p =>
p.ATTRIBUTE15 == id).Select(jk=> new { jk.HEADER_ID_PK,
jk.VENDOR_ID,
jk.VENDOR_SITE_ID,
jk.VENDOR_NAME,
jk.ADDRESS_LINE1,
jk.ATTRIBUTE15
}).GroupBy(p => new { p.HEADER_ID_PK,
p.VENDOR_ID, p.VENDOR_SITE_ID,
p.VENDOR_NAME, p.ADDRESS_LINE1,
p.ATTRIBUTE15 }).Select(p => new {
header_id_pk = p.Key, invoice_id_pk =
_ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(k => k.HEADER_ID_PK ==
p.Key.HEADER_ID_PK).Select(c => new { c.APP_INVOICES_ID_PK,
c.INVOICE_TYPES,
c.IS_HOURLY }).ToList() }).ToList();
I figured it out, I just needed to add those master columns in my Group By clause.
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))))))));
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)
)
)
)
)
);