C#LINQ Contains()查询自动完成搜索框很慢

问题描述 投票:0回答:2

我有一个搜索框,我正在提供自动填充建议,但它确实很慢,需要几秒钟才能显示建议。我很确定我的代码效率低下但是我不确定改进它的最佳方法,有什么建议吗?

[HttpPost]
    [Route("search")]
    public virtual JsonResult Search(string term)
    {
        var result = new List<SearchResult>();

        if (!String.IsNullOrWhiteSpace(term))
        {
            var searchTerms = term.ToLower().Split(' ');
            List<Card> resultList = null;
            foreach (var query in searchTerms)
            {
                if (resultList == null)
                {
                    resultList = CardRepository.FindAll().Where(x => x.Name.ToLower().Contains(query) || x.Set.SetName.ToLower().Contains(query) || x.Variant.ToLower().Contains(query) 
                    || x.CardNumber.ToLower().Contains(query) || (query == "holo" && x.IsHolo)).ToList();
                }
                else
                {
                    resultList = resultList.Where(x => x.Name.ToLower().Contains(query) || x.Set.SetName.ToLower().Contains(query) || x.Variant.ToLower().Contains(query) 
                    || x.CardNumber.ToLower().Contains(query) || (query == "holo" && x.IsHolo)).ToList();
                }
            }

            foreach (var item in resultList.Take(10))
            {
                result.Add(new SearchResult()
                {
                    label = item.FullCardName,
                    value = item.CardId.ToString()
                });
            }
        }

        return Json(result);
    }

编辑:添加了FindAll()代码。

 private readonly IDatabase _database;
 public IQueryable<Card> FindAll()
 {
     return _database.CardDataSource.OrderBy(a => a.Name).AsQueryable();
 }

解决方案:继续评论的建议并参考这篇文章Full Text Search with LINQ我将搜索作为一种方法移动到存储库,结果几乎是即时自动完成建议。我不确定我能在性能上做得多好,但它在当前状态下很容易使用。

public Card[] Search(string[] searchTerms)
{
    IQueryable<Card> cardQuery = _database.CardDataSource;
    foreach(var term in searchTerms)
    {
        var currentTerm = term.Trim();
        cardQuery = cardQuery.Where(p => (p.Name.Contains(currentTerm) ||
                                            p.Variant.Contains(currentTerm) ||
                                            p.CardNumber.Contains(currentTerm) ||
                                            p.Set.SetName.Contains(currentTerm) ||
                                            (term == "holo" && p.IsHolo) ||
                                            (term == "reverse" && p.IsHolo))
                                        );
    }

    return cardQuery.Take(10).ToArray();
}

[HttpPost]
[Route("search")]
public virtual JsonResult Search(string term)
{
    var result = new List<SearchResult>();

    if (!String.IsNullOrWhiteSpace(term))
    {
        var searchTerms = term.ToLower().Split(' ');
        var resultList = CardRepository.Search(searchTerms);

        foreach (var item in resultList)
        {
            result.Add(new SearchResult()
            {
                label = item.FullCardName,
                value = item.CardId.ToString()
            });
        }
    }

    return Json(result);
}
c# performance linq
2个回答
0
投票

我认为主要的问题是你正在使用返回.FindAll()List<T>

这意味着当你说CardRepository.FindAll()它将所有记录都记录到内存列表中,然后你的后续精炼查询(例如Where(x => x.Name.ToLower().Contains(query))等)都会针对整个列表运行。所以它回归真的很慢是对的。

您可以尝试通过简单地删除.FindAll()来重写它,看看会发生什么。

请注意,我只是给你一个主要问题,还有其他问题,但没有一个像这个一样重要。


-4
投票

您可以像这样使用多线程(伪C#代码):

var allCards = CardRepository.FindAll().ToArray(); // Ensure array.
query = query.ToUpper();

var nameTask = Task.StartNew(() => allCards.Where(x => x.Name.ToUpper().Contains(query)).ToArray());
var setTask = Task.StartNew(() => allCards.Where(x => x.Set.SetName.ToUpper().Contains(query)).ToArray());
var variantTask = Task.StartNew(() => allCards.Where(x => x.Variant.ToUpper().Contains(query)).ToArray());
var cardNumberTask = Task.StartNew(() => allCards.Where(x => x.CardNumber.ToUpper().Contains(query)).ToArray());
var holoTask = Task.StartNew(() => allCards.Where(x => query == "holo" && x.IsHolo).ToArray());

Task.WaitAll(new Task[] {nameTask, setTask, variantTask, cardNumberTask, holoTask});

var result = (nameTask.Result + setTask.Result + variantTask.Result + cardNumberTask.Result + halaTask.Result).Distinct().ToArray();
© www.soinside.com 2019 - 2024. All rights reserved.