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.