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))
);
Related
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 quire data from elastic and I get a big bunch of information.
I would like to get only two properties with values (key value pairs): timestamp and value, but I get lots, all the other information too.
How can I require only my properties I want? I tried like I read at elastic.co, but I still get always to full bunch of data.
Here my tries:
var result = ElasticClient.Search<_doc>(document =>
document
.Source(sf => sf
.Includes(i => i
.Fields(
f => f.Timestamp,
f => f.Value
)
)
.Excludes(e => e
.Fields(
f => f.ContextName
)
)
)
.Query(q => q
.Match(m => m
.Field(f => f.DataRecordId)
.Query(search)
)
)
);
Or:
var result = ElasticClient.Search<_doc>(document =>
document
.StoredFields(sf => sf
.Fields(
f => f.Timestamp,
f => f.Value
)
)
.Query(q => q
.Match(m => m
.Field(f => f.DataRecordId)
.Query(search)
)
)
);
Both return a big bag of data, much more than only Timestamp and Value.
So I get still all properties, but the excluded ones are null. I hope I will reduce traffic this way for better performance.
I'm open to other solutions.
var result = ElasticClient.Search<_doc>(document =>
document
.Source(src => src
.Includes(i => i
.Fields(
p => p.Timestamp,
p => p.Value
)
)
.Excludes(e => e
.Fields(
p => p.ComponentId,
p => p.ContextName,
p => p.DataRecordId,
p => p.ResourceId
)
)
)
.Query(q => q
.Match(m => m
.Field(f => f.DataRecordId)
.Query(search)
)
)
);
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)
)
)
);
}
I am trying to implement "Did you mean" feature like google in my windows desktop application.
I have created a POC which inserts "Name" and "Description" in my index say "MyIndex"
I am able to do full text search, but unable to do something like "Did you mean".
here is a code snipt that I found in NEST documentation and i am unable to understand it:
s => s
.Suggest(ss => ss
.Term("my-term-suggest", t => t
.MaxEdits(1)
.MaxInspections(2)
.MaxTermFrequency(3)
.MinDocFrequency(4)
.MinWordLength(5)
.PrefixLength(6)
.SuggestMode(SuggestMode.Always)
.Analyzer("standard")
.Field(p => p.Name)
.ShardSize(7)
.Size(8)
.Text("hello world")
)
.Completion("my-completion-suggest", c => c
.Contexts(ctxs => ctxs
.Context("color",
ctx => ctx.Context(Project.First.Suggest.Contexts.Values.SelectMany(v => v).First())
)
)
.Fuzzy(f => f
.Fuzziness(Fuzziness.Auto)
.MinLength(1)
.PrefixLength(2)
.Transpositions()
.UnicodeAware(false)
)
.Analyzer("simple")
.Field(p => p.Suggest)
.Size(8)
.Prefix(Project.Instance.Name)
)
.Phrase("my-phrase-suggest", ph => ph
.Collate(c => c
.Query(q => q
.Inline("{ \"match\": { \"{{field_name}}\": \"{{suggestion}}\" }}")
.Params(p => p.Add("field_name", "title"))
)
.Prune()
)
.Confidence(10.1)
.DirectGenerator(d => d
.Field(p => p.Description)
)
.GramSize(1)
.Field(p => p.Name)
.Text("hello world")
.RealWordErrorLikelihood(0.5)
)
)
what is color, doing here?
Also what is this " ctx => ctx.Context(Project.First.Suggest.Contexts.Values.SelectMany(v => v).First()"
and this ".Prefix(Project.Instance.Name)".
Am I on the right path?
Please help.
The did you mean feature is more likely Term suggester (https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-term.html)
Completion is autocompletion. When you write "so" in searchbox it will give you "sony", "soly" ..etc. So in this case you wont need this feature.
(https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html)
Phrase is advanced Term suggester, phrase gives you to choice pre-selected suggestions with a mapping as document says
(https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html)
You need this snippet in nest
s => s
.Suggest(ss => ss
.Term("my-term-suggest", t => t
.MaxEdits(1)
.MaxInspections(2)
.MaxTermFrequency(3)
.MinDocFrequency(4)
.MinWordLength(5)
.PrefixLength(6)
.SuggestMode(SuggestMode.Always)
.Analyzer("standard")
.Field(p => p.Name)
.ShardSize(7)
.Size(8)
.Text("hello world")
))
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)
)
)
)
)
)
);