Elastic Search - Reverse match query - c#

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()))))));

Related

Optimizing loading complex tree from DB with EF Core

Initial query structure:
var a = await _Db.A
.Include(a => a.B)
.ThenInclude(b => b.C1)
.ThenInclude(c1 => c1.D)
.Include(a => a.B)
.ThenInclude(b => b.C2)
.SingleOrDefaultAsync(a => a.Id == id);
The problem is that because B has two sub trees the result of the generated query has a row for each combination of the values from these subtrees. Two separate queries would give two results that are in total much smaller. So I tried, to load the second tree separately with
an explicit load.
var a = await _Db.A
.Include(a => a.B)
.ThenInclude(b => b.C1)
.ThenInclude(c1 => c1.D)
.SingleOrDefaultAsync(a => a.Id == id);
_Db.Entry(a).Collection(a => a.B).Query()
.Include(b => b.C2);
How ever the explicit load does nothing, I guess because B is already filled and it never checks if C2 needs filling. So is there anyway to get this to work?
The database provider is Npgsql. An Npgsql specific solution would be acceptable but a native EF core solution would be preferred.

Performance of .Include in LINQ

Which one is more efficient considering speed?
This one:
var studentWithBatchName =
db.Student.AsNoTracking()
.Include(c => c.Department)
.Include(c => c.Department.Section)
.Include(c => c.Department.Section.Batch)
.Select(c => c.Name, c.Department.Section.Batch.Name);
or this one:
var studentWithBatchName =
db.Student.AsNoTracking()
.Include(c => c.Department.Section.Batch)
.Select(c => c.Name, c.Department.Section.Batch.Name);
The Include statement is just getting the data from the related datasources/tables. If you are saying Include(c => c.Department.Section.Batch) you get the .Department.Section.Batch values.
If you are using .Include(c => c.Department).Include(c => c.Department.Section).Include(c => c.Department.Section.Batch)
it would theoretically add 3 joins to the query. I don't know if .NET catches these circumstances, but I would consider using ONLY Include(c => c.Department.Section.Batch) when you only need this value.
Found .ProjectTo to be more efficient considering speed. Instead of using Include which acts like outer join and makes your query big putting load on the server one can use .ProjectTo<>
Can get .ProjectTo<> by
using AutoMapper.QueryableExtensions;
Eg. var response = await db.TableName.ProjectTo().ToListAsync();

How to use and , or operator(&&, ||) in elasticsearch c#

I am trying to search records in Nest, my conditions are, expiration_date can be null or it can be within some date(ex. 10-20-2018) and effective_date can be some date (09-20-2018).
Below is my query, here I am not able to use || and && operator, either syntax issue, or my approach is wrong, can anyone help me with this?
docs = await _client.SearchAsync<PriceList>(s => s.Index(config.elasticsearchIndex)
.Query(a => a.Bool(c=>c.Should(
d => d.Bool(e => e.MustNot(f=>f.Exists(g => g.Field(h => h.ExpirationDate))))
||
.Query(a => a.DateRange(r => r.Field(field => field.ExpirationDate).GreaterThanOrEquals(forThisRange.fromDate)))
)))
.Query(a => a.DateRange(r => r.Field(field => field.EffectiveDate).LessThanOrEquals(forThisRange.toDate)))
My nest version is 6.4
UPDATED Query:
.Query(a => a.Bool(c=>c.Should(
d => d.Bool(e => e.MustNot(f=>f.Exists(g => g.Field(h => h.ExpirationDate))))
,
d=>d.Bool(e=>e.Must(f=>f.DateRange(r => r.Field(field => field.ExpirationDate).GreaterThanOrEquals(forThisRange.fromDate))))
//i=>i.DateRange
)))
.Query(a => a.DateRange(r => r.Field(field => field.EffectiveDate).LessThanOrEquals(forThisRange.toDate)))
I am not getting any error, but not getting extra record,it is giving correct result + "expiration_date" has less than 10-20-2018,the later should not.
Thanks all for your comments.
I found the solution, replace .Query() with .PostFilter() which resolved the issue. Don't know the exact difference between them, but it worked.
If anybody knows it, please comment it, may be helpful to others.

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))
));

Anyway to select both recent posts and recent threads

I am using LINQ and chain this command into a model.
model.LatestPosts = db.TPGForums.SelectMany(m => m.TPGForumTopics)
.SelectMany(m => m.TPGForumPosts)
.SelectMany(m => m.TPGForumThreads)
.OrderByDescending(m => m.dateCreated)
.Take(5);
This however only brings me back the Threads. I would need the last 5 most recent items in the TPGForumPosts and the TPGForumThreads. How would I return the most recent 5 posts/threads instead of just the most recent threads?
Nest the SelectMany calls, rather than chaining them:
var query = db.TPGForums
.SelectMany(forum => forum.TPGForumTopics
.SelectMany(topic => topic.TPGForumPosts
.SelectMany(post => post.TPGForumThreads
.Select(thread => new { forum, topic, post, thread }))))
.OrderByDescending(m => m.thread.dateCreated)
.Take(5);

Categories

Resources