I'm using Nest to connect to ElasticSearch and perform some queries. Until now, I've been able to get the results I'm asking for given a single wildcard query as below:
var searchResults = _client.Search<MyIndexable>(
body =>
body
.Index("someIndex")
.Query(
query =>
query.QueryString(
qs => qs.
OnFields(f => f.Title, f => f.Description)
.Query(searchTerm + "*"))));
But now I need to add additional conditions to my query for a certain usecase.
What I need is not only to query by [searchTerm]* but also two
other fields matching:
searchTerm + "*"
field1 = "some string"
field2 = "some Guid"
I'm sure there must be a way to do this in elastic search (using Nest) but I haven't been able to find it.
I know I can add the two additional fields to the index (as in someIndex_field1_field2) and that is definitely an option for me since field1 and field2 are decent partitions (and in fact, it may be a much better option to allow better partitioning) but I just wanted to see if there was a way to avoid doing this and instead, if it was possible to add multiple conditions to the query.
Does anyone know how to achieve this?
Many thanks,
Assuming field1 and field2 are just another fields like Title and Description, you can use bool must query to achieve what you want.
var searchResults = _client.Search<MyIndexable>(s => s
.Query(q => q
.Bool(b => b
.Must(
subQuery => subQuery.QueryString(qs => qs.OnFields(f => f.Title, f => f.Description).Query(searchTerm + "*"")),
subQuery => subQuery.Term(f => f.field1, "some string"),
subQuery => subQuery.Term(f => f.field2 , "some Guid")))));
Related
I'm trying to find a QueryContainer query that I can perform on an ElasticSearch result that will essentially filter out any "A" status Items in my resultset. My ProductIndex document contains a field named "StatusCode", and I don't want to return these "A" status' to my search resultsets... I'm having the hardest time finding a way to remove these items.
This query properly finds these "A" status':
.Match(qm => qm
.Field(f => f.StatusCode)
.Query("A"));
But I want to do the opposite (not get all the "A" status items, but exclude them)
Based upon other threads I read on here, I came up with the following query, but it's not filtering out these results:
.Bool(b => b
.MustNot(mn => mn
.Terms(t => t
.Field(f => f.StatusCode)
.Terms("A")
)
));
and
.Bool(b => b
.MustNot(mn => mn
.Term(t => t
.Field(f => f.StatusCode).Value("A")
)
));
But neither removes results that have an "A" statuscode
Kibana value of a result that is still being returned, but has the status "A" code:
The MustNot filter continues to not work for me - I ended up resolving this by performing two search queryies - one based upon the result set obtained from from the first query
.Match(qm => qm
.Field(f => f.StatusCode)
.Query("A"));
This properly filtered the items to only return the ones I was trying to remove from my primary query. I obtained this document list, then applied this list as an exclusion filter to my underlying request, thus filtering out the items I no longer wanted to return.
Not as elegant as I would like, but got the job done.
I have 2 elastic search queries that need to be matched by each fetched document in different ways. The "pools" query is a terms query. Each document has a list of pools attached to it, each of them being a string, and at least one of those pools must be in the provided list of pools in the "pools" query.
The other query is actually composed of multiple queries and at least 75% percent of them should be matched.
So in order for a document to be matched, the "pools" query must always be matched and from the other query, at least 75% must be matched.
I wrote my query like this:
var matchQuery = BuildQuery(searchCriteria);
var poolQuery = BuildPoolsQueryField(searchCriteria);
// prepare the data for elasticsearch
var result = await _elasticSearchClient.SearchAsync<ElasticPersonEntity>(
p => p.Query(q => q
.Bool(b => b.Must(poolQuery).Should(matchQuery.ToArray())
.MinimumShouldMatch(MinimumShouldMatch.Percentage(75))))).ConfigureAwait(false);
But I could not find anywhere on the internet if you can chain multiple Should and Must clauses and what it happens if you chain them like this.
According to your description, your query is wrong: you need to mustpoolQuery && matchQuery(75%) so
The .MinimumShouldMatch(MinimumShouldMatch.Percentage(75) should be inside your matchQuery :
I join an example (using my data, but this should solve your problem)
.Query(q => q
.Bool(b => b
.Must(
mu => mu.Term(te => te.CntCd, "FR"),
mu => mu.Bool(bo => bo
.Should(your should query).MinimumShouldMatch(75)
)
)
)
)
Im new to elastic-stack and want to implement global search on my indexed models and this is what I came up with at the moment:
var response = _client.Search<IndexBase>(s => s
.Type(Types.Type(typeof(A), typeof(B)))
.Query(qry => qry
.Bool(b => b
.Must(m => m
.QueryString(qs => qs
.DefaultField("_all")
.Query(request.Query)))))
.Highlight(h =>
h.Fields(f => f.Field("_all")))
But no highlights is showing up in my hits for documents. What Im doing wrong? How I can retrieve [index, count] pairs for highlighting?
Try replacing "_all" in the highlighter with *
var response = _client.Search<IndexBase>(s => s
.Type(Types.Type(typeof(A), typeof(B)))
.Query(qry => qry
.Bool(b => b
.Must(m => m
.QueryString(qs => qs
.DefaultField("_all")
.Query(request.Query)))))
.Highlight(h =>
h.Fields(f => f.Field("*")))
You are not indexing the fields properly.
In order to perform highlighting, the actual content of the field is required. If the field in question is stored (has store set to true in the mapping) it will be used, otherwise, the actual _source will be loaded and the relevant field will be extracted from it.
The _all field cannot be extracted from _source, so it can only be used for highlighting if it mapped to have store set to true.
Source
Also for any bigger set of data this can cause a performance drop so it's always better to set the search fields in the proper way and know what you are trying to highlight.
I'm setting up a system where my search indexed objects are Entities which map back to a normalized SQL database. So on the SQL side I may have a Company which is linked to one or more Company_Address records, as well as Company_Email records, etc. But all of the relevant searchable fields will be in a single Company indexed document tying back to the Company's unique id field.
I'm trying to setup queries which will return the relevant id based on comparing a user provided query string with specific fields in the indexed document. I can do so with a query similar to:
var searchResponse = this.client.Search<Company>(search => search.Query(
s => s.MultiMatch(
m => m.Query(query.QueryString)
.Fields(f => f.Field(c => c.Name).Field("Address1")) // Magic strings go here
.Fuzziness(Fuzziness.Auto)
)).Index<Company>());
I'd like to be able to replace "Address1" with ca.Address1 where ca is a CompanyAddress object. Is there a way to construct a collection of FieldDescriptor objects with multiple backing types and then supply that to the search query?
You can construct a Fields instance in a number of ways:
Building a Fields instance by chaining Field instances, constructing those from member access Lambda expressions on some type T
var searchResponse = this.client.Search<Company>(search => search
.Query(q => q
.MultiMatch(m => m
.Query("query")
.Fields(
Infer.Field<Company>(c => c.Name)
.And<CompanyAddress>(c => c.Address1)
)
.Fuzziness(Fuzziness.Auto)
)
)
.Index<Company>()
);
Using nameof with the Address1 property of CompanyAddress
var searchResponse = this.client.Search<Company>(search => search
.Query(q => q
.MultiMatch(m => m
.Query(query.QueryString)
.Fields(f => f
.Field(c => c.Name)
.Field(nameof(CompanyAddress.Address1))
)
.Fuzziness(Fuzziness.Auto)
)
)
.Index<Company>()
);
In orchard cms i want to write a query containing two condition over two different ContentPartRecord combined with OR clause. one possible way to combine conditions is :
var query = _contentManager.HqlQuery()
.Where(a => a.ContentPartRecord<ProductPartRecord>(), a => a.Eq("Title", "myTitle"))
.Where(a => a.ContentPartRecord<TitlePartRecord>(), a => a.Eq("Price", 1000))
.List();
but this one combines two condition with And clause. i think something like following along with some changes (which would be the answer for this question) could be the case:
var query = _contentManager.HqlQuery()
.Join(a => a.ContentPartRecord<ProductPartRecord>())
.Join(a => a.ContentPartRecord<TitlePartRecord>())
.Where(a => a.ContentItem(),
a => a.Or(p => p.Eq("ProductPartRecord.Price",
"1000"), t => t.Eq("TitlePartRecord.Title", "myTitle")))
.List();
but i couldn't get it working.any body have any suggestion?
When you use where clause in HqlQuery you need to pass Alias (as first parameter). Alias means that you will be apply where clause to specific table (class that represent this table). And when you use OR clause that you definitely need to compare columns of the specific table in two parts of OR clause (left and right from the OR clause). And i think this is not possible to do you need a standard way.
But you can use:
Action<IAliasFactory> productPartRecordAlias = x => x.ContentPartRecord<ProductPartRecord>().Named("productPartRecord");
Action<IAliasFactory> titlePartRecordAlias = x => x.ContentPartRecord<TitlePartRecord>().Named("titlePartRecord");
var query = _contentManager.HqlQuery()
.Join(productPartRecordAlias)
.Join(titlePartRecordAlias)
.Where(a => a.ContentItem(), p => p.Gt("Id", "0 AND (productPartRecord.Price = 1000 OR titlePartRecord.Title = 'myTitle')"));