I have an application where I am taking a large number of 'product names' input by a user and retrieving some information about each product. The problem is, the user may input a partial name or even a wrong name, so I want to return the closest matches for further selection.
Essentially if product name A exactly matches a record, return that, otherwise return any contains matches. Otherwise return null.
I have done this with three separate statements, and I was wondering if there was a more efficient way to do this. I am using LINQ to EF, but I materialize the products to a list first for performance reasons.
productNames is a List of product names (input by the user). products is a List of product 'records'
var directMatches = (from s in productNames
join p in products on s.ToLower() equals p.name.ToLower() into result
from r in result.DefaultIfEmpty()
select new {Key = s, Product 开发者_开发知识库= r});
var containsMatches = (from d in directMatches
from p in products
where d.Product == null
&& p.name.ToLower().Contains(d.Key)
select new { d.Key, Product = p });
var matches = from d in directMatches
join c in containsMatches on d.Key equals c.Key into result
from r in result.DefaultIfEmpty()
select new {d.Key, Product = d.Product ?? (r != null ? r.Product: null) };
If you have a small to medium-sized list in-memory, take a look at LiquidMetal and for phonetic matches, the Soundex algorithm to rank the closest matches.
If you are using SQL Server, look into Full-Text Search, which is what Stack Overflow uses. Otherwise, here is how I implemented a keyword-based search.
精彩评论