如何查询SQL数据库中的短语?

时间:2017-11-28 21:18:58

标签: mysql sql

我正在使用MySQL ,我有一个歌曲的SQL数据库,其中一个表格包含一列歌曲的8列信息。每一行代表歌词中的一个单词:

  1. songSerial - 歌曲的序列号

  2. songName - 歌曲名称

  3. word - 歌曲歌词中的单词

  4. row_number - 找到该字词的行数

  5. word_position_in_row - 单独行中的单词编号

  6. house_number - 该字所属的房屋编号

  7. house_row - 在

    中找到该单词的房子中的行号
  8. word_number - 所有歌曲歌词中的字数

  9. 一排的例子:{4,科学家,秘密,8,4,2,1,37}

    现在我想查询包含一组单词的所有歌曲。例如,所有带有句子的单词:"我爱你"在他们中。 必须按顺序,而不是来自不同的行或房屋。

    以下是我的oneDrive中用于创建数据表和大约400行的脚本: TwoTextScriptFilesAndTheirZip

    有人可以帮忙吗?

    谢谢

3 个答案:

答案 0 :(得分:1)

一种方法是使用join s:

select s.*
from songwords sw1 join
     songwords sw2
     on sw2.songSerial = sw1.songSerial and
        sw2.word_number = sw1.word_number + 1 join
     songwords sw3
     on sw3.songSerial = sw2.songSerial and
        sw3.word_number = sw2.word_number + 1 
where sw1.word = 'I' and sw2.word = 'love' and sw3.word = 'you';

或者,如果您愿意:

where concat_ws(' ', sw1.word, sw2.word, sw3.word) = 'I love you'

从优化角度来看情况更糟(使用word的索引无法帮助提高性能),但很清楚查询正在做什么。

此类型的搜索建议使用full text index。唯一需要注意的是,无论长度如何,您都需要删除停用词列表并索引所有单词。 (“我”和“你”是停止词的典型例子。)

答案 1 :(得分:0)

对于大型表,这是一种昂贵的方法,假设word不为空,我们可以这样做:

SET group_concat_max_len = 16777216 ;

SELECT t.song_serial
     , t.house_number
     , t.row_number
  FROM mytable t
 GROUP
    BY t.songserial
     , t.house_number
     , t.row_number
HAVING CONCAT(' ',GROUP_CONCAT(t.word ORDER BY t.word_position_by_row),' ') 
  LIKE CONCAT('% ','I love you',' %')

我们肯定想要一个合适的索引,例如

... ON `mytable` (`songserial`,`house_number`,`row_number`,`word`) 

如果短语中的一个单词不常见,我们可能首先搜索该不常用的单词来优化一点,然后将所有单词放在同一行...

SELECT t.song_serial
     , t.house_number
     , t.row_number
  FROM ( SELECT r.songserial
              , r.house_number
              , r.row_number
           FROM mytable r
          WHERE r.word = 'love'
          GROUP
             BY r.word
              , r.songserial
              , r.house_number
              , r.row_number
       ) s
  JOIN mytable t 
    ON t.songserial   = s.songserial 
   AND t.house_number = s.house_number
   AND t.row_number   = s.row_number
 GROUP
    BY t.songserial
     , t.house_number
     , t.row_number
HAVING CONCAT(' ',GROUP_CONCAT(t.word ORDER BY t.word_position_by_row),' ') 
  LIKE CONCAT('% ','I love you',' %')

内联视图s将受益于覆盖索引,其中word为前导列

... ON `mytable` (`word`,`songserial`,`house_number`,`row_number`)

答案 2 :(得分:0)

你寻找这些单词和相对搜索位置:1 = I,2 =爱,3 =你。让我们将它们与两首歌曲进行比较:

            And I love, love, love you
real pos:   1   2 3     4     5    6
search pos: -   1 2     2     2    3
diff:       -   1 1     2     3    3

            I miss you and I love you
real pos:   1 2    3   4   5 6    7
search pos: 1 -    3   -   1 2    3
diff:       0 -    0   -   4 4    4

如果我们查看第一行的位置增量,我们得到1(两次),2(一次)和3(两次)。

对于第二行,我们得到增量0(两次)和4(三次)。

因此,对于第二首歌曲,我们找到一个与搜索词一样多的匹配的delta,而不是第一行。第二行是匹配。

这是查询。我假设我们有一个临时表search填充了搜索词和相对位置以便于阅读。

select distinct w.songserial, w.songname, w.house_number
from words w
join search s on s.word = w.word
group by
  w.songserial, w.songname, w.row_number, w.house_number, w.house_row, -- song line
  w.word_position_in_row - s.pos -- delta
having count(*) = (select count(*) from search);

此查询基于:

  • 一首歌由songserial + songname + house_number
  • 标识
  • 歌曲行由songserial + songname + row_number + house_number + house_row
  • 标识

这可能是错的;我不知道参考歌曲的房子和门牌号是什么意思。但这很容易调整。