【问题标题】:SQL LIKE, how to sort results by weighted occurrence count?SQL LIKE,如何按加权出现次数对结果进行排序?
【发布时间】:2011-02-24 11:35:02
【问题描述】:

我有我的搜索词:

"Yellow large widgets"

我将这些术语分成三个词:

1 = "Yellow";
2 = "Large";
2 = "Widgets";

然后我搜索:

SELECT * FROM widgets
    WHERE (description LIKE '%yellow%' OR description LIKE '%large%' OR description LIKE 'widgets') 
    OR (title LIKE '%yellow%' OR title LIKE '%large%' OR title LIKE '%widgets%')

如何根据这些偏差对结果进行排序?

  • 标题占主导地位,如果任何术语出现在标题中,它们应该被认为更重要
  • 出现次数,总出现次数较高的结果应首先出现

理想方法

  • 计数description 中的出现次数。
  • 这里的每一次出现都值得1 point
  • 计数title 中的出现次数。
  • 每个title 的出现都值得5 points
  • 按分数排序。

但我不知道在 SQL 中从哪里开始。

【问题讨论】:

  • 使用 LIKE 是绝对要求还是您会考虑替代方案?
  • @Mark 我很乐意考虑替代方案,喜欢它是我熟悉的唯一搜索术语。我也用可能的解决方案编辑了这个问题。
  • 抱歉不得不回滚,因为我把它格式化得更好。不过我的拼写很糟糕:(

标签: sql sql-order-by search-engine


【解决方案1】:

好的,让我们将您的搜索词放在一个临时表中:

CREATE TABLE #SearchTerms (Term varchar(50) not null)
insert into #SearchTerms (Term)
select 'yellow' union all
select 'large' union all
select 'widgets'

让我们做点傻事吧:

select
    widgets.ID,
    (LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) as DescScore
    (LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) as TitleScore
from
    widgets,#SearchTerms

我们现在已经计算了描述和标题中每个术语的每次出现次数。

所以现在我们可以对这些事件进行汇总和加权:

select
    widgets.ID,
    SUM((LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) +
    ((LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) *5)) as CombinedScore
from
    widgets,#SearchTerms
group by
    Widgets.ID

如果我们需要对此做更多的事情,我建议将上述内容放在子选择中

select
    w.*,CombinedScore
from
    widgets.w
       inner join
    (select
        widgets.ID,
        SUM((LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) +
        ((LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) *5)) as CombinedScore
    from
        widgets,#SearchTerms
    group by
        Widgets.ID
    ) t
        on
            w.ID = t.ID
where
    CombinedScore > 0
order by
    CombinedScore desc

(请注意,我假设在所有这些示例中都有一个 ID 列,但可以将其扩展为在小部件表中定义 PK 所需的尽可能多的列)


这里真正的技巧是计算一个词在更大的文本正文中出现的次数,这是通过以下方式完成的:

(LEN(text) - LEN(text with each occurrence of term removed)) / LEN(term)

【讨论】:

  • 很棒的答案,我今晚会好好浏览一下并玩一下。
【解决方案2】:

选择以下选项之一:

  • 使用全文搜索引擎(Lucene 或类似的)进行加权全文搜索;
  • this other StackOverflow question
  • 做多个SELECTs,每个都有一个relevance字段,将它们与UNION合并并排序结果;
  • 检索结果后,在应用程序中对结果进行排序。

【讨论】:

    【解决方案3】:

    快速破解(对于 mysql,您可以在其他数据库上使用类似的构造)。注意,未经测试。

    SELECT description, title
      FROM
    (SELECT description, title,
            IF(description LIKE '%yellow%' OR 
               description LIKE '%large%' OR 
               description LIKE 'widgets' 2, 0) +
            IF(title LIKE '%yellow%' OR 
               title LIKE '%large%' OR
               title LIKE '%widgets%', 1, 0) AS w
      FROM widget)
     WHERE w > 0
    ORDER BY w
    

    【讨论】:

      【解决方案4】:

      也许这样

         SELECT description, title ,
                  (       IF(title LIKE '%yellow%', 2, 0) +
                  IF(title LIKE '%large%', 2, 0) +
                  IF(title LIKE '%widgets%', 2, 0)+       IF(description LIKE '%yellow%', 1, 0) +
                  IF(description LIKE '%large%', 1, 0) +
                  IF(description LIKE '%widgets%', 1, 0)      )   AS w 
      
          FROM widget ORDER BY w DESC
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 2012-05-22
        • 1970-01-01
        • 2018-03-19
        • 2011-09-28
        • 2017-02-21
        • 1970-01-01
        相关资源
        最近更新 更多