MultiSearch Query Syntax Using NEST API Elasticsearch - elasticsearch

Does anyone know the syntax for using MultiSearch using the NEST library version 7.6.
We have tried:
var result = client.MultiSearch(ms => ms
.Search<ElasticsearchProject>("projects", s => s.MatchAll())
.Search<Person>("people", s => s.MatchAll())
);
It seems this is not valid anymore in version 7.6

MultiSearch expects an Indices as the first parameter, although it is an optional parameter. To pass just the delegate, label the parameter
var result = client.MultiSearch(selector: ms => ms
.Search<ElasticsearchProject>("projects", s => s.MatchAll())
.Search<Person>("people", s => s.MatchAll())
);

var d = new MultiSearchDescriptor();
d.Search<ElasticsearchProject>("projects", s => s
.Index("<indexname>")
.Query(q => q
.MatchAll()
)
.From(1)
.Size(10)
);
d.Search<Person>("people", s => s
.Index("<indexname>")
.Query(q => q
.MatchAll()
)
.From(1)
.Size(10)
);
var re = _elasticClient.MultiSearch(d);

Related

Should + Must combination query using NEST client for elastic

I have a requirement to get data based on combination of properties with OR and AND combination and i am not able to get this query done. Help me with what it should be like in json and also using NEST client.
SQL query:
Select *
From MySourceTable
Where (flag1 In ("Y","N")
And EntityStatus In ("STAT1", "STAT2")
And EntityType In ("T3"))
Or (flag1 In ("N") And EntityType In ("T1", "T2"))
So far my query builds all must queries which resulted in fewer or none results. So theoretically I believe each query is MUST queries and all must queries have to be merged using OR.
Help me build json
You are on a good way, the query will look something like
var searchResponse = await elasticClient.SearchAsync<EsDocument>(s => s
.Query(q =>
(
q.Terms(t => t.Field(f => f.Flag1.Suffix("keyword")).Terms("Y", "N")) &&
q.Terms(t => t.Field(f => f.EntityStatus.Suffix("keyword")).Terms("STAT1", "STAT2")) &&
q.Terms(t => t.Field(f => f.EntityType.Suffix("keyword")).Terms("T3"))
) ||
(
q.Terms(t => t.Field(f => f.Flag1.Suffix("keyword")).Terms("N")) &&
q.Terms(t => t.Field(f => f.EntityType.Suffix("keyword")).Terms("T1", "T2"))
)));
You didn't share your index mapping and query, so hard to say why your query didn't work.
UPDATE
You can compose such query dynamically using the following
var should = new QueryContainer();
should |=
(
new TermsQuery { Field = Infer.Field<EsDocument>(f => f.Flag1.Suffix("keyword")), Terms = new []{ "Y", "N" }} &&
new TermsQuery { Field = Infer.Field<EsDocument>(f => f.EntityStatus.Suffix("keyword")), Terms = new []{ "STAT1", "STAT2" }} &&
new TermsQuery { Field = Infer.Field<EsDocument>(f => f.EntityType.Suffix("keyword")), Terms = new []{ "T3" }}
);
should |=
(
new TermsQuery { Field = Infer.Field<EsDocument>(f => f.Flag1.Suffix("keyword")), Terms = new []{ "N" }} &&
new TermsQuery { Field = Infer.Field<EsDocument>(f => f.EntityType.Suffix("keyword")), Terms = new []{ "T1", "T2" }}
);
var searchResponse = await elasticClient.SearchAsync<EsDocument>(s => s
.Query(q => should));

Query with '-' returns incorrect results in ElasticSearch NEST 7.x

Here is the query I use to search:
var response = await client.SearchAsync<MenuForElasticSearch>(searchDescriptor => searchDescriptor
.Query(queryContainerDescriptor => queryContainerDescriptor
.Bool(queryDescriptor => queryDescriptor
.Should(queryStringQuery => queryStringQuery.Match(match => match.Field(fld => fld.DisplayName).Query(query)),
queryStringQuery => queryStringQuery.Wildcard(wildcard => wildcard.Field(flds => flds.DisplayName).Value($"*{query}*")),
queryStringQuery => queryStringQuery.Fuzzy(fuzzy => fuzzy.Field(flds => flds.DisplayName).Value(query)))
)));
There are three documents with displayName = NPW-711, NPW-677 and NPW-777. When I search NPW-711 it returns all three documents.
Can adding DefaultOperator(Elasticsearch.Net.DefaultOperator.And) help? If yes, where it fits?
Match query with AND operator will give you what you are looking for
var results = await client.SearchAsync<Document>(s => s
.Query(q => q
.Match(m => m
.Field("name")
.Query(query)
.Operator(Operator.And))));
output:
Results for query "NPW-777": NPW-777
Results for query "NPW": NPW-711,NPW-677,NPW-777
Results for query "677": NPW-677
Hope that helps.

Async way of implementing search query in Elastic Search Nest Client .NET

I have implemented a Search Query through NEST client and was able to get the records. The code is as follows.
var response = clientProvider.Client.Search<ProjectModel>(s => s
.Index("project_index")
.Type("projects")
.Source(so => so.Excludes(f => f.Field(x => x.FileInfo.FileBase64Data)))
.Size(100)
.Query(q => q
.Bool(b => b
.Should(
m => m.QueryString(qs => qs
.Query(searchOptions.SearchTerm)
.Fields(ff => ff.Fields(fields))
.Fuzziness(Fuzziness.Auto)
),
m => m.MultiMatch(qs => qs
.Query(searchOptions.SearchTerm)
.Type(Nest.TextQueryType.PhrasePrefix)
.Fields(ff => ff.Fields(fields))
)
)
)
)
.Sort(ss => ss.Descending(SortSpecialField.Score))
);
And I am mapping the response to my Project Model as follows.
var project = response.Hits.Select(h =>
{
h.Source._id = h.Id;
h.Source.Score = h.Score;
return h.Source;
}).ToList();
When I am trying to implement the same Search in Async way that is
var response = clientProvider.Client.SearchAsync<ProjectModel>(s => s
.Index("project_index")
.Type("projects")
.Source(so => so.Excludes(f => f.Field(x => x.FileInfo.FileBase64Data)))
.Size(100)
.Query(q => q
.Bool(b => b
.Should(
m => m.QueryString(qs => qs
.Query(searchOptions.SearchTerm)
.Fields(ff => ff.Fields(fields))
.Fuzziness(Fuzziness.Auto)
),
m => m.MultiMatch(qs => qs
.Query(searchOptions.SearchTerm)
.Type(Nest.TextQueryType.PhrasePrefix)
.Fields(ff => ff.Fields(fields))
)
)
)
)
.Sort(ss => ss.Descending(SortSpecialField.Score))
);
I am not getting any errors while executing it. But I am not able to get the response.Hits objects to map it back to my original Project Model.
Thanks In advance
In SearchAsync<T>(), response is Task<ISearchResponse<T>>, so you probably want to await it
Map all documents, found in products index, onto ProductDto type:
var result = await _elasticClient.SearchAsync<ProductDto>(x => x.Index("products").MatchAll());
var documents = result.Documents;

ElasticSearch C# client (NEST): Filtering results with ES 5.5.0

This was my code in the earlier version of ES it used to work. After moving to ES 5.5. It has stopped working and it gives a compiler error.
Error: 'QueryStringQueryDescriptor' does not contain a definition for 'OnFields' and no extension method 'OnFields' accepting a first argument of type 'QueryStringQueryDescriptor'
Below is my code snippet...
public List<EmployeeInfo> SearchText2(string query, List<string> sendersList, int page = 0, int pageSize = 50)
{
try
{
var result = this.client.Search<EmployeeInfo>(s => s
.From(page * pageSize)
.Size(int.MaxValue)
.Query(q => q
.QueryString(qs => qs.Query(query).UseDisMax()
.OnFields(b => b.Subject)
.OnFields(b => b.Body)
))
.SortDescending(f => f.ReceivedTime)
.Filter(f => f.Terms(ak => ak.SenderName, sendersList))
);
...
// Some code here
}
Any tips on how to make this work will be great.
In latest version of Nest library there are some API changes
Instead of OnFields in QueryString you should use Fields
QueryString(qs => qs.Query(string.Empty).UseDisMax()
.Fields(descriptor => descriptor.Fields(b => b.Subject, b => b.Body))
))
Instead of SortDescending you should use Sort
.Sort(descriptor => descriptor.Field(f => f.ReceivedTime, SortOrder.Descending))
Also the filters are not available in elasticsearch starting from version 5 and you should use bool query with filter
Query(descriptor =>
descriptor.Bool(boolQuery =>
boolQuery
.Must(query => query.MatchAll())
.Filter(f => f.Terms(ak => ak.SenderName, sendersList)
)
)
)

Elasticssearch Nest Synonyms 2.XX

I'm a newbie for elasticsearch and we are evaluate elasticsearch for our webstore. One important feature is the usage of synonyms. Unfortunately I'm not able to create a index with synonyms. Please can anybody help me how I can use the synonyms feature. I didn't find any sample for this feature and elasticsearch 2.xx. The goal should be if I search for Hills the entry of Royal will be find.
I use the following code:
private ElasticClient GetClient()
{
var node = new Uri(ES_URI);
var uri = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(uri).DefaultIndex("product");
var client = new ElasticClient(settings);
return client;
}
public void CreateSynonymIndex()
{
Product product = new Product()
{
Id = "2",
ProductName = "Royal",
Description = "Katzenfutter für Nierkranke"
};
var client = GetClient();
client.DeleteIndex("product");
var syn = new[] { "royal, hills => royal" };
ICreateIndexResponse respose = client.CreateIndex("product", c => c
.Mappings(mp => mp.Map<Product>(d => d.
Properties(p => p.String(n => n.Name(name => name.ProductName).Index(FieldIndexOption.Analyzed)))))
.Settings(s => s
.Analysis(an => an
.Tokenizers(at=>at.Pattern("synonymTokenizer",pa=>pa.Pattern("Test")))
.Analyzers(a=>a.Custom("synonymAnalyser",ca =>ca
.Tokenizer("synonymTokenizer")
.Filters(new List<string> { "synonym" })))
.TokenFilters(tf => tf
.Synonym("synonym", sy => sy.Synonyms(syn)
.Tokenizer("whitespace")
.IgnoreCase(true)))))
);
client.Index(product);
}
public void ES_Search()
{
var client = GetClient();
var response = client.Search<Product>(search => search
.Query(q => q.Bool(b => b
.Should(
// s => s.Match(m => m.Query("sometest").Field(f => f.ProductName).Boost(1.1)),
s => s.Match(m => m.Query("hills").Field(f => f.ProductName).Fuzziness(Fuzziness.EditDistance(1)))
))));
var response1 = client.Search<Product>(s => s.Query(q => q.Term(p => p.ProductName, "hills")));
}
Regards,
Dominik
You have created analyzer with synonyms, but you are not using it. You need to tell elasticsearch that ProductName field should use synonymAnalyser analyzer.
.Mappings(mp => mp.Map<Product>(d => d.
Properties(p => p.String(n => n
.Name(name => name.ProductName)
.Analyzer("synonymAnalyser")
.Index(FieldIndexOption.Analyzed)))))
I noticed few more things though:
remeber that document is not immediately available in elasticsearch after calling client.Index(..) method. It will take some miliseconds. Searching just right after indexing document, you may not find it. You can read more about it here
I don't know if you creat ElasticClient with default index, because you didn't share it. If not, you will have to specify it in your search calls e.g.
client.Search<Product>(s => s.Index("product")).
Hope that helps you.

Resources