按相关性/排名对搜索结果进行排序

时间:2019-01-07 12:07:29

标签: c# sql-server linq search full-text-search

我已经用C#创建了一个.net MVC应用程序,该应用程序列出了组织,当前在数据库(SQLServer)中有6000条记录。组织表中的字段为:

  • 标题(酒精支持小组)
  • ContactPerson(詹姆斯·邦德)
  • 内容(我们为酗酒者提供支持)
  • 关键字(酒精,成瘾,酗酒)

当前搜索是使用linq完成的,例如:

iList<Organisation> orglist = myOrgs.Where(x => x.Title.Contains('abc') || 
                                                x.ContactPerson.Contains('abc') || 
                                                x.Details.Contains('abc') || 
                                                x.Keywords.Contains('abc'))
                                    .OrderBy(x => x.Title).ToList();

然后按标题对结果进行排序。哪个不合适。

如果有人搜索“酒精支持”,我希望以上结果在列表顶部。

我希望对以下结果进行排名:

  1. 组织标题中的完整句子匹配。
  2. 组织标题中的所有搜索词。
  3. 组织标题中的任何搜索词。
  4. 组织关键字中的任何搜索词。
  5. 组织内容中的完整句子匹配。

正在寻找实现此目标的最佳方法的建议,或者是否有人知道已经有这样做的算法/库?

**更新** 我现在正在寻找一个更简单的解决方案,请参见以下链接:

Sorting collection based on keywords with Linq

1 个答案:

答案 0 :(得分:0)

摘要:

  • 需求的

    • R01 |标题|全部匹配|按顺序
    • R02 |标题|完全匹配|以任何顺序
    • R03 |标题|任何匹配项|
    • R04 |关键字|任何匹配项|
    • R05 |内容|全场比赛|
  • 对于每种要求,我们将进行SQL调用

  • 每个SQl调用我们将仅返回行ID的

  • 然后我们按顺序将ID分组

  • 我们将进行最终的SQL调用


步骤01:R01

  • 在这里我们将使用EF

    db.Orgs.Where(w => w.Title.Contains(search_query))
    .Select(s => s.Id).ToList();
    

这种对linq2Sql的使用包含将转换为sql WHERE IN

步骤02:R02

  • 在这里我们将使用普通sql 位置 + 喜欢 + AND

    Select Id From Orgs where 
    Title LIKE '%' + @param0 +'%' 
    and Title LIKE '%' + @param1 +'%' 
    

步骤03:R03

  • 在这里我们将使用普通sql 位置 + + 并且

    Select Id From Orgs 
    where Title LIKE '%' + @param0 +'%'  
    or  Title LIKE '%' + @param1 +'%' 
    

步骤04:R04

  • 在这里我们将使用普通sql 位置 + + 并且

    Select Id From Orgs 
    Where Keywords LIKE '%' + @param0 +'%' 
    or  Keywords LIKE '%' + @param1 +'%' 
    

步骤05:R05

  • 在这里我们将使用EF

        db.Orgs
        .Where(w => w.Content.Contains(search_query)).
        Select(s => s.Id).ToList();
    

这种对linq2Sql的使用包含将转换为sql WHERE IN

步骤06-将ID分组并忽略可重复的人

  • 使用行ID的步骤1至5

我们将根据订单检索对ID进行排序

        var ids = new Dictionary<int, int>();

        foreach (var id in Ids1)
        {
            int val;
            if (!ids.TryGetValue(id, out val))
            {
                ids.Add(id, ids.Count());
            }

        };
        .
        .

步骤07-重新订购

         ids.OrderByDescending(o => o.Value)
        .Select(s => s.Key) .ToArray();

步骤08-现在我们使用Oredred ID来获取数据

  • 在这里我们将使用普通sql 订购依据 + 随后的情况

    Select * from Orgs 
    where  Id in ( 2 , 1 )  
    ORDER BY CASE id  
    WHEN 2 THEN 0 
    WHEN 1 THEN 1 
    ELSE 2 END
    

第09步完整代码


    using System;
    using System.Collections.Generic;
    using System.Linq;

    namespace ConsoleApp9
    {
    class Program
    {
    static void search(string search_query)
    {
    //////////////////////////////////////////////////
    var terms = search_query.Split(' ');
    //////////////////////////////////////////////////
    var Ids1 = db.Orgs.
    Where(w => w.Title.Contains(search_query))
    .Select(s => s.Id).ToList();

    var Ids2 = db.Database
    .SqlQuery<int>(getWhere("Title", "AND"), terms)
    .ToList();

    var Ids3 = db.Database
    .SqlQuery<int>(getWhere("Title", "OR"), terms)
    .ToList();

    var Ids4 = db.Database
    .SqlQuery<int>(getWhere("Keywords", "OR"), terms)
    .ToList();

    var Ids5 = db.Orgs
    .Where(w => w.Content.Contains(search_query))
    .Select(s => s.Id).ToList();

    var ordered_ids = reorderList(Ids1, Ids2, Ids3, Ids4, Ids5);

    var OrderedData = db.Database.SqlQuery<Org>(getOrdered(ordered_ids)).ToList();

    //////////////////////////////////////////////////

    foreach (var item in OrderedData)
    {
        Console.WriteLine($"{item.Id} - {item.Title} - {item.ContactPerson } - {item.Keywords } - {item.Content  }");

    }

    //////////////////////////////////////////////////
    Console.ReadLine();
    //////////////////////////////////////////////////
    string getWhere(string _column, string _oprator)
    {
        var val = "Select Id From Orgs where ";
        for (int i = 0; i < terms.Length; i++)
        {
            if (i > 0) val += @" " + _oprator + " ";
            val += @" " + _column + " LIKE '%' + {" + i + "} +'%'  ";
        }
        return val;
    }
    //////////////////////////////////////////////////
    string getOrdered(int[] _ids_ordered)
    {
        var val = "Select * From Orgs where ";
        val += " Id in ";
        for (int i = 0; i < _ids_ordered.Length; i++)
        {
            if (i == 0) val += "( ";
            if (i > 0) val += " , ";
            val += _ids_ordered[i];
            if (i == terms.Length - 1) val += " ) ";
        }
        val += " ORDER BY CASE id ";
        for (int i = 0; i < _ids_ordered.Length; i++)
        {
            val += " WHEN " + _ids_ordered[i] + " THEN " + i;
        }
        val += " ELSE " + _ids_ordered.Length + " END ";

        return val;
    }
    //////////////////////////////////////////////////
    int[] reorderList(List<int> _Ids1, List<int> _Ids2,
        List<int> _Ids3, List<int> _Ids4, List<int> _Ids5)
    {
        var idsDic = new Dictionary<int, int>();

        var idsArr = new List<int>[5] { Ids1, Ids2, Ids3, Ids4, Ids5 };
        for (int i = 0; i < 5; i++)
        {
            idsArr[i].ForEach(id =>
            {
                if (!idsDic.TryGetValue(id, out int val))
                    idsDic.Add(id, idsDic.Count());
            });
        };
        var o_ids = idsDic.OrderByDescending(o => o.Value)
                .Select(s => s.Key).ToArray();
        return o_ids;
    }
    }

    static Model1 db = new Model1();

    static void Main(string[] args)
    {
    string search_quer = "Alcohol Support";
    Console.WriteLine($"searching for {search_quer}");
    search("Alcohol Support");
    }
    }


    }

注释01:SQL注入

  • 什么是Sql注入

      

    SQL注入是一种代码注入技术,用于攻击   数据驱动的应用程序,其中包含恶意的SQL语句   插入要执行的输入字段

注释01.01:问题

注释01.02:Microsoft文档

  • 摘自Microsoft文档:How to: Directly Execute SQL Queries | Microsoft Docs

      

    使用相同的参数在查询文本中表示   Console.WriteLine()和String.Format()使用的卷曲表示法。在   实际上,String.Format()实际上是在您查询的字符串上调用的   提供,将花括号参数替换为生成的   参数名称,例如@ p0,@ p1…,@ p(n)。   enter image description here

注释01.03:在此项目中

  • 使用EF 6.2时

    var sql2 = " Select Id From Orgs where ";
    for (int i = 0; i < terms.Length; i++)
    {
        if (i > 0) sql2 += @" and ";
        sql2 += @" Title LIKE '%' + {" + i + "} +'%'  ";
    }
    
  • 将生成:

    Select Id From Orgs where  
    Title LIKE '%' + {0} +'%'   
    and  Title LIKE '%' + {1} +'%'  
    
  • 在使用 SQL Server Profiler

    的sqlserver中
    exec sp_executesql N' Select Id From Orgs where  
    Title LIKE ''%'' + @p0 +''%''   and  Title 
    LIKE ''%'' + @p1 +''%''  ',N'@p0 nvarchar(7)
    ,@p1 nvarchar(7)',@p0=N'Alcohol',@p1=N'Support'
    

注释01.04:另一种格式

  • 我们还可以使用SqlParameter类

    var sql4 = " Select Id From Orgs where  ";
    var sql4_parameter = new List<SqlParameter>();
    for (int i = 0; i < terms.Length; i++)
    {
        if (i > 0) sql4 += @" or ";
        sql4 += @" Keywords LIKE '%' + @param" + i + " +'%'  ";
        sql4_parameter.Add(new SqlParameter("param" + i, terms[i]));
    }
    
  • 这是sql

     Select Id From Orgs 
     Where Keywords LIKE '%' + @param0 +'%' 
     or  Keywords LIKE '%' + @param1 +'%'