【问题标题】:How to perform word search using LINQ?如何使用 LINQ 执行单词搜索?
【发布时间】:2015-07-14 18:29:54
【问题描述】:

我有一个包含供应商名称的列表。说

SuppId   Supplier Name
----------------------------------
1        Aardema & Whitelaw
2        Aafedt Forde Gray
3        Whitelaw & Sears-Ewald

使用以下 LINQ 查询

supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey));

我可以在以下情况下正确返回记录,

1) 如果我使用搜索字符串作为 "Whitelaw & Sears-Ewald",它将返回第三条记录。

2) 如果我使用 "Whitelaw" 或 "Sears-Ewald",它将返回第三条记录。

但是,如果我将搜索字符串指定为 “Whitelaw Sears-Ewald”,我如何返回第三条记录。它总是返回 0 条记录。

我可以使用 ALL 来获得这个结果,但我不知道如何使用它来满足这个特殊需要。

【问题讨论】:

  • 打造智能搜索引擎绝非易事。有很多语言解析和逻辑进入其中,远远超过单个 LINQ 语句。
  • 您需要的是模糊搜索,而 LINQ 并没有开箱即用。阅读此stackoverflow.com/questions/13162830/…
  • 您是否要求将“Whitelaw”和“Sears-Ewald”视为单独的搜索词并返回包含至少一个搜索词的任何记录?
  • @Max 是的,即有时用户可以使用“Whitelaw Sears-Ewald”代替“Whitelaw & Sears-Ewald”进行搜索。但在这两种情况下,我们都需要返回第三条记录
  • 我建议为此使用 RegEx。您可以根据输入构建一个模式,例如 pattern= String.split(" ",input).select(s=>"("+s+")").join(" ")

标签: c# linq


【解决方案1】:

在这种情况下我通常做的是将单词拆分成一个集合,然后执行以下操作:

var searchopts = SearchKey.Split(' ').ToList();
supplierListQuery = supplierListQuery
    .Where(x => searchopts.Any(y=> x.SupplierName.Contains(y)));

【讨论】:

  • 对我来说似乎很合理,-1 中的任何一个会详细说明吗?
  • 这太有用了。谢谢
  • 当单词用空格分隔并且搜索请求不包含比搜索发生的单词更长的单词时,这种方法非常好。例如,它不适用于搜索查询: 1. “WhitelawSears-Ewald”,因为它在单词之间没有空格。 2. “Aafedtzzzzz”,因为它比单词“Aafedt”长,所以“Aafedt”不能包含它。
  • 您可以简单地将 x.SupplierName.Contains(y) 与 y.Contains(x.SupplierName) 交换以允许这样做
【解决方案2】:

这对我有用:

IEnumerable<string> keyWords = SearchKey.Split('');

supplierListQuery = supplierListQuery
      .AsParallel()
      .Where
      (
         x => keyWords.All
         (
              keyword => x.SupplierName.ContainsIgnoreCase(keyword)
         )
      );

【讨论】:

    【解决方案3】:

    感谢大家的快速回复。但是解决这个问题的一个有效或简单的解决方法是 timothyclifford 对此的说明。就像他说的那样,我改变了对此的回答

    string[] filters = SearchKey.ToLower().Split(new[] { ' ' });
    objSuppliersList = (from x in objSuppliersList
                        where filters.All(f => x.SupplierName.ToLower().Contains(f))
                        select x).ToList();
    

    现在它返回我所有搜索条件的结果。

    【讨论】:

    • 尝试搜索“Aafedtzzzzz”或“WhitelawSears-Ewald”,看看是否有任何结果;)
    • @Fabjan 是的,你是对的,但是当我遵循 Juann Strauss 的方法时,当我使用 serach 键作为“Whitelaw Sears-Ewald PLLC”时,我无法找到结果。您的方法的问题是我的数据库中有超过 10000 条供应商记录,每次用户单击 serach 按钮时,我都需要对这些记录执行搜索。我还需要考虑过滤查询。所以我对整体表现感到紧张。
    • 通过使用 timothyclifford 的方法,现在我可以处理我的基本搜索查询。所以我暂时采用这种方法。谢谢你通知我这件事。 :)
    • LINQ 在性能方面并不是很好。小心使用它,当您可以使用联合/析取与单个查询获得相同的结果时,请避免多个查询,例如: .Where(condition1).Where(condition2).Where(condition3) 你可以这样做 .Where(condition1 ||条件2 || 条件3) 结果相同。
    【解决方案4】:

    因为“Whitelaw”出现在两者中,您将获得两条记录。否则没有动态的方法来确定你只想要最后一个。如果您知道您只有这 3 个,则附加 .Last() 以获取最终记录。

    供应商列表查询 = 供应商列表查询.Where(x => x.SupplierName.Contains(SearchKey.Split(' ')[0]));

    【讨论】:

    • 您选择的答案仅有效,因为 Whitelaw 在您的字符串中排在第一位。进行真正的搜索时,您会希望它找到与 Whitelaw 匹配的所有记录,然后从那里过滤以找到您想要的记录。您可以很容易地做到这一点:supplierListQuery = supplierListQuery..Where(x => x.SupplierName.StartsWith(SearchKey.Split()[0]));只获取与查询中第一个单词匹配的记录。
    【解决方案5】:

    您需要使用某种字符串比较器来创建自己的简单搜索引擎,然后您可以找到最有可能包含在结果中的字符串:

    public static class SearchEngine
    {
    
        public static double CompareStrings(string val1, string val2)
        {
            if ((val1.Length == 0) || (val2.Length == 0)) return 0;
            if (val1 == val2) return 100;
    
            double maxLength = Math.Max(val1.Length, val2.Length);
            double minLength = Math.Min(val1.Length, val2.Length);
            int charIndex = 0;
            for (int i = 0; i < minLength; i++) { if (val1.Contains(val2[i])) charIndex++; }
    
            return Math.Round(charIndex / maxLength * 100);
        }
    
        public static List<string> Search(this string[] values, string searchKey, double threshold)
        {
            List<string> result = new List<string>();
            for (int i = 0; i < values.Length; i++) if (CompareStrings(values[i], searchKey) > threshold) result.Add(values[i]);
            return result;
        }
    }
    

    使用示例:

    string[] array = { "Aardema & Whitelaw", "Aafedt Forde Gray", "Whitelaw & Sears-Ewald" };
    
    var result = array.Search("WhitelawSears-Ewald", 80);
    // Results that matches this string with 80% or more
    
    foreach (var item in result)
    {
       Console.WriteLine(item);
    }
    

    输出:Whitelaw &amp; Sears-Ewald

    【讨论】:

      【解决方案6】:

      如果您想要一个简单(不是很方便)的解决方案,

      var result = supplierListQuery
                            .Select(x => normalize(x.SupplierName))
                            .Where(x => x.Contains(normalize(SearchKey)));
      
      string normalize(string inputStr)
      {
          string retVal = inputStr.Replace("&", "");
          while (retVal.IndexOf("  ") >= 0)
          {
              retVal = retVal.Replace("  ", " ");
          }
          return retVal;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-20
        • 2018-04-07
        • 2021-05-01
        • 2016-02-16
        • 1970-01-01
        • 2020-12-27
        相关资源
        最近更新 更多