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)
)
)
)
)
)
);
Related
My Elasticsearch document looks like this; I have created an average aggregation in the buckets of 60 seconds interval
{
"version" : 4,
"metric1" : 0.688872,
"metric2" : 0.021005,
"metric3" : 0.578913,
"metric4" : 71.57523,
"metric5" : 10.71166,
"Agentid" : "12345",
"epoch" : 1638173827064
}
My Aggregation Code looks like this;
var response = await _client.SearchAsync<MyPOCO>(s => s
.Index(indexName)
.TrackTotalHits(true)
.Size(0)
.Query(q => q
.Bool(b => b
.Must(mu => mu
.Match(m => m
.Field("AgentId")
.Query(Convert.ToString(AgentId))
)
)
.Filter(fi => fi
.DateRange(r => r
.Field("epoch")
.GreaterThanOrEquals(Convert.ToString(StartTime))
.LessThan(Convert.ToString(EndTime))
.Format("epoch_millis")
)
)
)
)
.Aggregations(a => a
.DateHistogram("metricsperminute", ab => ab
.Field("ts")
.FixedInterval("1m")
.Aggregations(x => x
.Average("metric1", m => m
.Field(o => o.metric1)
)
.Average("metric2", n => n
.Field(o => o.metric2)
)
.Average("metric3", o => o
.Field(o => o.metric4)
)
.Average("metric5", p => p
.Field(o => o.metric5)
)
)))
.Sort(sort => sort.Ascending("epoch")));
I am a bit lost in how to fetch more than 10k records/buckets in the aggregations ? How to do pagination or scrolling ? Please help.
There is a search.max_buckets dynamic cluster setting though I'd try to avoid returning too many buckets at once. It's extremely slow
Currently working on a project involving a vehicle database.
We have set up some filters for the end users to select, such as chassis, transmission, price. Which works as intended
Now we are trying to implement a autocomplete feature in the search field. Since the simple query string will require a complete modelname and or brandname, I have looked into completion and that works for an unfinished brand name ie: "tesl" will suggest the respective Tesla models.
What I'm struggling with is getting the suggestions within the specified query.
Thanks!
Solution:
Not sure if this is the correct way to solve it, but I just ran the main query with the suggested ids to get the full payload to get all the data i need for the text search.
var result = await _client.SearchAsync<Models.VehicleModel>(descriptor => descriptor
.Index("vehiclemodel")
.Query(
q =>
q
.Terms(t => t
.Name("ModelName")
.Field("modelName")
.Terms(searchArguments.Models)
)
&&
q
.Terms(t => t
.Name("BrandName")
.Field("brandName")
.Terms(searchArguments.Brands)
)
&&
q
.Range(t => t
.Name("Price")
.Field("modelMinimumPrice")
.GreaterThanOrEquals(searchArguments.MinPrice)
.LessThanOrEquals(searchArguments.MaxPrice)
)
&&
q
.SimpleQueryString(c => c
.Name("textquery")
.Query(searchArguments.Query)
.Boost(2)
.Fields(f => f
.Field(p => p.BrandName + "^2")
.Field(p => p.ModelName + "^2")
.Field(p => p.EnergySource)
.Field("*")
)
)
public async Task<dynamic> GetModelSearchSuggestions(SearchArguments searchArguments = default)
{
var result = await _client.SearchAsync<dynamic>(s => s
.Index("vehiclemodel")
.Suggest(su => su
.Completion("searchsuggest", cs => cs
.Field("suggest")
.Prefix(searchArguments.Query)
.Fuzzy(f => f
.Fuzziness(Fuzziness.Auto)
)
)
)
);
return result.Suggest;
}
mappingDescriptor
.Properties(p => p
.Completion(cp => cp
.Name("suggest")
.Analyzer("standard")
.SearchAnalyzer("standard")
)
.Text(t => t.Name("modelName").Fielddata(true))
.Text(t => t.Name("brandName").Fielddata(true))
);
I'm pretty new to Elastic Search and stumbled upon this issue.
When searching multiple document types from the same index, the types are getting appended in the result documents set instead of being default sorted by boosted field.
My document types shares the same fields.
This is my search query:
var response = await client.SearchAsync<ProductListResponse>(s => s
.Type("product,productbundle")
.Index(index)
.From(from)
.Size(size)
.Query(fsq => fsq
.FunctionScore(c => c.Query(q => q
.MultiMatch(m => m.Query(request.Query)
.Fields(f => f
.Field(n => n.Name, 100.0)
.Field(n => n.NameWithoutSpecialChars, 100.0)
.Field(n => n.ProductName)
.Field(n => n.TeaserText)
.Field(n => n.Description)
.Field(n => n.Features)
.Field(n => n.Modules)
)
.Type(TextQueryType.PhrasePrefix)
)
).Functions(f => f
.FieldValueFactor(b => b
.Field(p => p.IsBoosted)
.Modifier(FieldValueFactorModifier.Log1P))
)
)
)
.Sort(ss => ss
.Descending(SortSpecialField.Score))
.PostFilter(filter => filter.Bool(b => b.Must(must => allFilters)))
.Source(sr => sr
.Include(fi => fi
.Field(f => f.Name)
.Field(n => n.ProductName)
.Field(n => n.TeaserText)
.Field(f => f.Image)
.Field(f => f.Thumbnail)
.Field(f => f.Url)
.Field(f => f.Features)
)
)
);
Any help is appreciated.
I would preferre not to adapt the product type with the additons to productbundle type..
I can confirm that .Type() does not mess with the order.
My issue was a boosted property not getting a value while indexing the bundles.
I am having some trouble with a certain query in elastic search C#.
I have this QueryContainer, with an inner QueryDescriptor and alot of inner QueryContainers \ QueryDescriptors,
but one main QueryContainer => this._QueryContainer that contains all the data.
the thing is, that the field UserID is not unique in this._QueryContainer, so when i return 20 unique users, first time all is ok, but next 20 users (for next page) i wouldn't know where to start this.From...
because the this._QueryContainer has duplicates but return unique because of aggregation. so there is a conflict.
Is there a way to make the query distinct from the start?
results = Client.Search<Users>(s => s
.From(this.From)
.Query(this._QueryContainer)
.Aggregations(a => a
.Terms("unique", te => te
.Field(p => p.UserID)
)
)
.Size(20)
);
The .From() and .Size() within your query do not affect the Terms aggregation that you have, they apply only to the .Query() part and the hits returned from this.
If you need to return lots of values from a Terms aggregation, which is what I think you'd like to do, you can
1.Use partitioning to filter values, returning a large number of terms in multiple requests e.g.
var response = client.Search<Users>(s => s
.Aggregations(a => a
.Terms("unique", st => st
.Field(p => p.UserID)
.Include(partition: 0, numberOfPartitions: 10)
.Size(10000)
)
)
);
// get the next partition
response = client.Search<Users>(s => s
.Aggregations(a => a
.Terms("unique", st => st
.Field(p => p.UserID)
.Include(partition: 1, numberOfPartitions: 10)
.Size(10000)
)
)
);
2.Use a Composite Aggregation with a Terms value source
var response = client.Search<Users>(s => s
.Aggregations(a => a
.Composite("composite", c => c
.Sources(so => so
.Terms("unique", st => st
.Field(p => p.UserID)
)
)
)
)
);
// the following would be in a loop, to get all terms
var lastBucket = response.Aggregations.Composite("composite").Buckets.LastOrDefault();
if (lastBucket != null)
{
// get next set of terms
response = client.Search<Users>(s => s
.Aggregations(a => a
.Composite("composite", c => c
.Sources(so => so
.Terms("unique", st => st
.Field(p => p.UserID)
)
)
.After(lastBucket.Key)
)
)
);
}
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?