I'm working on a project that searches parts using Elasticsearch and NEST (7.x). Here's my Model (adjusted for simplicity):
[ElasticsearchType]
public class PartInfo
{
public string Make { get; set; }
public string PartNo { get; set; }
public string Description { get; set; }
public string WebURL { get; set; }
public string Category { get; set; }
public string[] Keywords { get; set; }
public string[] FilterValue { get; set; }
public int SalesYTD { get; set; }
public bool IsDiscontinued { get; set; }
public string PartClass { get; set; }
[Ignore]
public double? Score { get; set; }
}
And the Index Creation routine (again edited for relevance):
public void IndexParts(IEnumerable<PartInfo> parts)
{
var deleteIndexResponse = _client.Indices.Delete("partinfo");
var createIndexResponse = _client.Indices.Create("partinfo", c => c.Map<PartInfo>(m => m.AutoMap()));
int batch = 1000;
foreach (var batches in parts.Batch(batch))
{
var response = _client.IndexMany(batches, "partinfo");
if (!response.IsValid) throw new Exception("Error Indexing!");
}
}
And finally my search query:
var filters = new List<Func<QueryContainerDescriptor<PartInfo>, QueryContainer>>();
filters.Add(f => f.Match(m => m.Field(fi => fi.PartClass).Query(partClass)));
if (!showDiscontinued) filters.Add(f => f.Term(m => m.Field(fi => fi.IsDiscontinued).Value(false)));
var result = _client.Search<PartInfo>(x => x.Index("partinfo").Query(q => q
.Bool(b => b
.Should(sh => sh
.MatchPhrasePrefix(m => m
.Field(fi => fi.PartNo)
.Query(query)
.Boost(100)
),
sh => sh
.Term(m => m
.Field(f => f.Category)
.Value(query)
.Boost(100)
),
sh => sh
.MatchPhrase(m => m
.Field(f => f.Category)
.Query(query)
.Boost(90)
),
sh => sh
.MatchPhrase(m => m
.Field(fi => fi.Description)
.Query(query)
.Boost(10)
),
sh => sh
.Term(t => t.Keywords, query, 10),
sh => sh
)
.Filter(filters)
)
)
.From(page - 1).Size(pageSize));
Here's my two goals:
- I need to be able to search against PartNo OR Category first, followed by Description and/or Keywords. PartNo should be by prefix, while the other queries can be any combination of words.
- For the results, I need them returned by both score/relevance AND by SalesYTD top to bottom - together. For example, same scoring items get sorted by higher sales first.
The problem is that the search and sortings aren't working as expected. I'm getting results scoring funny (a part search of 123 is scoring 12345 higher than actual matches of 123) and I can't set a sort without breaking the scoring entirely (adding ShowScores doesn't seem to help).
Any ideas?