ElasticSearch NEST OR query - c#

i've been having some trouble regarding creating a query that searches through different fields.
I got the answers i wanted by creating several queries - but for the sake of performance - i want to do this in just one query, if possible.
I've tried setting the query up in several .Should clauses, but it seems that it searches for documents that matches every field, which i think is intended.
It looks like this;
.From(0)
.Sort(sort => sort
.Field("priority", SortOrder.Descending))
.Sort(sort => sort
.Ascending(a => a.ItemNumber.Suffix("keyword")))
.Sort(sort => sort
.Descending(SortSpecialField.Score))
.TrackScores(true)
.Size(25)
.Query(qe => qe
.Bool(b => b
.Should(m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemnumber")
.Query(ItemNumber)
))
.Should(m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemnumber2")
.Query(ItemNumber)))
.Should(m => m
.Match(ma => ma
.Boost(1.1)
.Field("ean")
.Query(ItemNumber)))
.Should(m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemalias")
.Query(ItemNumber)))
)));
What i want it to do is; Search through the Itemnumber and see if a document matches, if not, search through the Itemnumber2 and so on.
Is there an efficient way to do this in just one query?

I believe the syntax for a should query with multiple parts should be an array of queries. Your way you would just add multiple separate should queries. What you want should probably look like this:
.Bool(b => b
.Should(
m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemnumber")
.Query(ItemNumber)),
m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemnumber2")
.Query(ItemNumber)),
m => m
.Match(ma => ma
.Boost(1.1)
.Field("ean")
.Query(ItemNumber)),
m => m
.Match(ma => ma
.Boost(1.1)
.Field("itemalias")
.Query(ItemNumber)))
More here

Have you tried using a MultiMatch query instead? https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
This would allow you to search your documents as you would with a Match query, but you should be able to specify multiple fields to search in.
This would allow you to ditch the bool query.

Related

How to apply date range to a aggregation query using Nest client

I am using Nest client to build an Aggregation query and able to get the results from the elasticsearch.
I have tried to add the date range to the query as follows. BUt while adding date range, Nest call becomes invalid.
Any suggestion that how to do add date range
``
var t = client.Search<USJob>(s => s
.Query(q => q
.Bool(b => b
.Filter(f => f
.Terms(t => t
.Field("RuleID")
.Terms(aggField)
), f => f
.Range(dr => dr
.Field(f => f.jobdate)
.GreaterThanOrEquals(20200801)
)
)
)
)
``
Try using the example code:
var query = new QueryContainerDescriptor<USJob>()
.Bool(b => b.Filter(f => f.DateRange(dt => dt
.Field(field => field.jobdate)
.GreaterThanOrEquals(birthdate)
.LessThanOrEquals(birthdate)
.TimeZone("+00:00"))));
It is very important to use TimeZone and limit LessThanOrEquals to not return all your index data.
And separate your queries by QueryContainerDescriptor, that way it's easy to find any inconsistencies.
References: https://github.com/hgmauri/elasticsearch-with-nest/blob/master/src/Sample.Elasticsearch.Domain/Applications/ActorsApplication.cs

elasticsearch NEST get nested document

situation is this. I have in elastic a group. each of these groups have a nested list of items.
Both group and items have an attribute named serial, which are unique.
I get a serial for the group and a serial for item, and with those 2 items i'm supposed to return the item.
Currently i'm doing it the following way:
public item findItem(string groupSerial, string itemSerial)
{
var searchResponse = _elasticClient.Search<Group>(s => s
.Index(_config.groupIndexName)
.Query(q => q
.ConstantScore(cs => cs
.Filter(f => f
.Term(t => t
.Field(fi => fi.serial)
.Value(groupSerial)
)
)
)
).Query(q => q
.Nested(c => c
.InnerHits(i => i.Explain())
.Path(p => p.items)
.Query(nq => nq.Term(t => t
.Field(field => field.items.First().serial)
.Value(itemSerial)))))
);
var result = searchResponse.Documents.FirstOrDefault();
return result?.items.Find(item => item.serial == itemSerial);
}
I get the feeling that there is supposed to be a more efficient way. Like getting the item straight from the search in elastic. Does anyone know how?

Elastic Search - Reverse match query

Currently I wrote a query against an elastic server to remove all documents with an old "BatchVersion". After thinking about it, to be safe, I want all records delete that don't equal the current "BatchVersion". Here is my current code
_client.DeleteByQuery<Data.ElasticSearch.Employee>(s => s
.Index(indexName)
.Size(1000)
.Query(q => q.
Bool(b => b.
MustNot(mn => mn.
Match(m => m.Field("BatchVersion").
Query([newVersionId]))))));
When the code is run, no records are deleted. Any ideas?
I had to use Default_Field for it to work. I used kibana to figure it out.
_client.DeleteByQuery<Employee>(s => s
.Index(indexName)
.Size(1000)
.Query(q => q.
Bool(b => b.
MustNot(mn => mn.
QueryString(qs => qs.DefaultField("batchVersion").Query(newVersionId.ToString()))))));

Elasticsearch NEST

Currently I started using Elasticsearch wrapper for c# "NEST", and I'm facing some troubles for writing queries that check for partial similarities such as in "book" and "books", so when I have a document that contains "books", if I search for "book" it doesn't find it:
here is my code :
var articles = client.Search<ProductResult>(s => s
.From(0)
.Size(1000)
.MatchAll()
.Query(q => q.QueryString(d => d
.Query(query)
)));
Try analyzing your fields with a stemming analyzer like snowball which will try it's best to reduce words to their root form. For example, books and booking => book, jumps and jumping => jump. etc... The algorithm behind it isn't perfect and will trip up on irregular words/plural forms, but for the most part it works very well (on most European languages).
You can apply different analyzers when you initially create your index, or on an existing index using the update mapping API. Either way, you'll have to reindex our documents to apply the new analysis.
Create index example using NEST:
client.CreateIndex("yourindex", c => c
...
.AddMapping<YourType>(m => m
.MapFromAttributes()
.Properties(ps => ps
.String(s => s.Name("fieldname").Analyzer("snowball"))
...
)
)
);
Update mapping example:
client.Map<YourType>(m => m
.MapFromAttributes()
.Index("yourindex")
.Properties(ps => ps
.String(s => s.Name("fieldname").Analyzer("snowball"))
...
)
);
Here's some really great info on algorithmic stemmers in The Definitive Guide.
U can use Fuzzy also...
var articles = client.Search<ProductResult>(s => s
.From(0)
.Size(1000)
.Query(q => q.(d => d
.Fuzzy(fz => fz.OnField("field").Value("book").MaxExpansions(2))
));

Multi Terms search NEST C#

I want to do a search matching multiple values ( an array of values ) like this :
var result1 = _client.Search<type1>(s => s
.Fields(f => f.trip_id)
.Query(q => q
.Terms(t => t.arg1, value1)).Take(_allData))
.Documents.Select(d => d.arg2).ToArray();
var result2 = _client.Search<type2>(s => s
.Query(q => q
.Terms(t => t.arg3, result1))
.Take(_allData)
).Documents.Select(s => s.ar3).ToList();
How can I do ? I was thinking about facets but I don't see how I can do it.
The only way for now that works is with a foreach iterator which is not really effective...
Thanks for your help.
You can express multiple queries like so:
.Query(q=>q.Terms(t=>t.arg3, result1) && q.Terms(t=>t.arg1, value1))
Be sure to read the documentation on writing queries to discover all the good stuff NEST has to offer.
Orelus,
I'd like to use your solution with
.And( af=>af.Term(...), af=>af.Term(...) )
I don't understand where this fits, here's an example of my non-working filter
var results = client.Search<music>(s => s
.Query(q => q
.Filtered(f => f.
Filter(b => b.Bool(m => m.Must(
t => t
.Term(p => p.artist, artist)
&& t.Term(p2 => p2.year, year)
)
)
)
)
)
);

Categories

Resources