Sort inside of a query or filter in elasticsearch - elasticsearch

I am using elasticsearch.net client. I query something with pagination. But it returns documents according to sorting criteria not query criteria.It is like it ignores the query just works with sorting. Thing is I want to sort all documents then process the query. I think if I can use sort inside of a query that'll solve the problem.Is there any way to do that? Thanks in advance.
Here is code piece.
ISearchResponse<Product> response = _elasticClient
.Search<Product>(p => p
.From(request.Pagination.PageIndex - 1)
.Size(request.Pagination.ItemCount)
.Query(q => q
.Bool(b => b
.Must(m => m.Term(genderTerm => genderTerm.ProductGenderTypeList, request.BoutiqueFilter.GenderTypeList ?? Enumerable.Empty<string>()))
.Should(s => s
.Match(m2 => m2
.OnField(on => on.ProductGenderType)
.Query((request.BoutiqueFilter.SortGender == SortGender.None ? String.Empty : ((int)request.BoutiqueFilter.SortGender).ToString()))
.Operator(Operator.And)))))
.Sort(sort => request.BoutiqueFilter.SortByPrice == SortByPrice.None
? sort.OnField(onf => onf.Sequence).Ascending()
: request.BoutiqueFilter.SortByPrice == SortByPrice.Ascending
? sort.OnField(onf => onf.Price).Ascending()
: sort.OnField(onf => onf.Price).Descending()));

Related

Query one field with multiple values in elasticsearch nest

I have a combination of two queries with Elasticsearch and nest, the first one is a full-text search for a specific term and the second one is to filter or query another field which is file-path but it should be for many files paths and the path could be part or full path, I can query one file-path but I couldn't manage to do it for many file paths, any suggestion?
Search<SearchResults>(s => s
.Query(q => q
.Match(m => m.Field(f => f.Description).Query("Search_term"))
&& q
.Prefix(t => t.Field(f => f.FilePath).Value("file_Path"))
)
);
For searching for more than one path you can use bool Query in elasticsearch and then use Should Occur to search like logical OR, so you code should look like this:
Search<SearchResults>(s => s
.Query(q => q.
Bool(b => b
.Should(
bs => bs.Wildcard(p => p.FilePath, "*file_Pathfile_Path*"),
bs => bs.Wildcard(p => p.FilePath, "*file_Pathfile_Path*"),
....
))
&& q.Match(m => m.Field(f => f.description).Query("Search_term")
)));
Also you should use WildCard Query to get result for paths that could be part or full path. For more information check ES offical documentation about WildQuery and Bool Query below:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/bool-queries.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html

How to construct Aggregation (Count) of records using NEST?

I have a requirement to perform Aggregation (Count) of records using NEST wrapper but to fire the DSL query inside NEST.
Since I don't know how to construct it properly, I have done the same using LINQ approach.
ISearchResponse<AgencyDetailReportModel> searchResponse = ConnectionToESClient().Search<AgencyDetailReportModel>
(s => s
.Index("accountsdata")
.From(0)
.Size(15000)
.Query(q =>
q.MatchAll()
)
);
var allocatedAgencies = agencySearchResponse.Documents.Where(w => !string.IsNullOrEmpty(w.agencyid)).Count();
var unAllocatedAgencies = agencySearchResponse.Documents.Where(w => string.IsNullOrEmpty(w.agencyid)).Count();
How can I construct the DSL query inside NEST?
So for your question you need allocatedAgencies count and unAllocatedAgencies count right.We can achieve this by simple query rather than going for aggregations.
var searchResponse = await highLevelClient.CountAsync<accountsdata>(s => s
.Index("accountsdata")
.Query(q => q
.ConstantScore(c => c
.Filter(f => f
.Bool(b => b
.MustNot(m => m
.Exists(e => e.Field("agencyid"))))))));
This is for unAllocatedAgencies count and for allocatedAgencies below is the query.
var searchResponse = await highLevelClient.CountAsync<accountsdata>(s => s
.Index("accountsdata")
.Query(q => q
.ConstantScore(c => c
.Filter(f => f
.Bool(b => b
.Must(m => m
.Exists(e => e.Field("agencyid"))))))));
Let me know if you face any issues, max it will work for your above mentioned problem. Thanks

ElasticSearch NEST custom word joiner Analyzer not returning the correct result

I created an autocomplete filter with ElasticSearch using NEST API. I cant seem to get the word joiner to work.
So basically if I search for something like Transhex i also want to be able to return Trans Hex
My Index looks as follow...I think the WordDelimiter filter might be wrong.
Also, I followed the following article Link. They use the low-level API so it is possible that I am doing it completely wrong using the NEST API
var response = this.Client.CreateIndex(
"company-index",
index => index.Mappings(
ms => ms.Map<CompanyDocument>(m => m.Properties(p => p
.Text(t => t.Name(n => n.CompanyName).Analyzer("auto-complete")
.Fields(ff => ff.Keyword(k => k.Name("keyword")))))))
.Settings(f => f.Analysis(
analysis => analysis
.Analyzers(analyzers => analyzers
.Custom("auto-complete", a => a.Tokenizer("standard").Filters("lowercase", "word-joiner-filter", "auto-complete-filter")))
.TokenFilters(tokenFilter => tokenFilter
.WordDelimiter("word-joiner-filter", t => t.CatenateAll())
.EdgeNGram("auto-complete-filter", t => t.MinGram(3).MaxGram(30))))));
UPDATE
So I updated the Analyzer to look as follows, noticed that I updated the Analyzer from standard to keyword.
var response = this.Client.CreateIndex(
this.indexName,
index => index.Mappings(
ms => ms.Map<CompanyDocument>(m => m.Properties(p => p
.Text(t => t.Name(n => n.CompanyName).Analyzer("auto-complete")
.Fields(ff => ff.Keyword(k => k.Name("keyword")))))))
.Settings(f => f.Analysis(
analysis => analysis
.Analyzers(analyzers => analyzers
.Custom("auto-complete", a => a.Tokenizer("keyword").Filters("lowercase", "word-joiner-filter", "auto-complete-filter")))
.TokenFilters(tokenFilter => tokenFilter
.WordDelimiter("word-joiner-filter", t => t.CatenateAll())
.EdgeNGram("auto-complete-filter", t => t.MinGram(1).MaxGram(20))))));
The Results will look as follows
Search Keyword : perfect pools
Results
perfect pools -> This is the correct one at the top
EXCLUSIVE POOLS
Perfect Painters
Search Keyword : perfectpools Or PerfectPools
Results
Perfect Hideaways (Pty) Ltd -> this is the wrong one i would like to display perfect pools
PERFORMANTA APAC PTY LTD
Perfect Laser Technologies (PTY) LTD
Use Keyword tokenizer. The standard tokenizer will split the word in 2 tokens, then apply the filters on them.
UPDATE:
I used a search like this one and seems ok.
var searchResult = EsClient.Search<CompanyDocument>(q => q
.Index("test_index")
.Type("companydocument")
.TrackScores(true)
.Query(qq =>
{
QueryContainer queryContainer = null;
queryContainer = qq.QueryString(qs => qs.Fields(fs => fs.Field(f => f.CompanyName)).Query("perfectpools").DefaultOperator(Operator.And).Analyzer("auto-complete"));
return queryContainer;
})
.Sort(sort => sort.Descending(SortSpecialField.Score))
.Take(10)
);

Number of records in index

I have an elasticsearch query method, but it only yields me 10 records of an index --- does someone know how I can get all the records that I have?
var consultaPlazaCobro = elasticClient.Search<Entity.PlazaCobroELK>(s => s
.Index("plazacobro")
.Type("logs")
.Query(q => q.QueryString(qs => qs.Query("*"))));
If you have less than 10000 documents, you can use the .Size() method call:
var consultaPlazaCobro = elasticClient.Search<Entity.PlazaCobroELK>(s => s
.Size(10000)
.Index("plazacobro")
.Type("logs")
.Query(q => q.QueryString(qs => qs.Query("*"))));
Otherwise you need to resort to using a Scroll request

Elasticsearch 2.1 - Deprecated search types

According to this link, both scan and count are deprecated.
I am trying to change my queries to reflect this. So the count change is easy, just removing the search type and adding size=0 to the request, however, I am not 100% on the scan change.
Currently I have this query:
var result = ElasticClient.Search<Product>(s => s
.From(0)
.Size(10)
.SearchType(SearchType.Scan)
.Scroll("4s")
.Query
(qu =>
qu.Filtered
(fil =>
fil.Filter
(f =>
f.Bool(b => b.Must(m => m.Term("filedName", "abc")))))));
Am I correct in my understanding that all I need to change is remove the searchtype and add a sort? I.e:
var result = ElasticClient.Search<Product>(s => s
.From(0)
.Size(10)
.Scroll("4s")
.Sort(x => x.OnField("_doc"))
.Query
(qu =>
qu.Filtered
(fil =>
fil.Filter
(f => f.Bool(b => b.Must(m => m.Term("filedName", "abc")))))));
I have seen a enum SortSpecialField here, but I am not sure how to actually use this in the sort parameter.
You're correct in your understanding that the change (as you document in your question) to sort by _doc will replace the deprecated Scan searchtype. The SortSpecialField enum is just syntax sugar for sorting by _doc. If you prefer to use it, in NEST 2.0 [only], you can do this:
ElasticClient.Search<Product>(s => s
.From(0)
.Size(10)
.Scroll("4s")
.Sort(x => x.Ascending(SortSpecialField.DocumentIndexOrder))
...

Resources