如何进行多个关键字搜索?

时间:2009-02-14 19:16:39

标签: sql loops while-loop

我有2个表要搜索。搜索照片以查找关键字,标题和说明。 关键字已拆分为单独的表格。我的高级搜索将允许搜索所有3个,但基本将只是关键字表。

基本表格设置:

照片表

  • PHOTOID
  • 名称
  • 标题
  • 描述

WORD2PHOTO表

  • 的wordID
  • PHOTOID

尝试查看和存储过程,并没有获得任何好结果。我从视图中得到了我的照片,但是在多个记录中。我会在应用程序端进行过滤和那些东西,但我使用亚音速并且想使用内置的分页;这是另一个问题。

首先,如何搜索多个关键字? 其次,如何添加搜索标题和描述?

我有一个函数(f_Split)将返回当前单词的临时表进行搜索,

DECLARE @Words TABLE (Word varchar(20))

INSERT INTO @Words (Word)
SELECT Keyword FROM dbo.f_Split('cars|auto|red|fast','|')

现在我如何使用它生成的表来获取照片记录? 一直在挣扎几天? 谢谢你的帮助。

5 个答案:

答案 0 :(得分:3)

假设你有桌子照片和桌子Word,并且使用附加表WordToPhoto有多对多的关系:

DECLARE @Photo TABLE
(ID INT, Name VARCHAR(20), Title VARCHAR(50), Description VARCHAR(200))
INSERT INTO @Photo 
SELECT 1, 'mountain.jpg', 'Mountain trip', 'Mountain trip'
UNION
SELECT 2, 'beach.jpg', 'On the beach', 'On the beach'
UNION
SELECT 3, 'garden.jpg', 'Garden', 'Garden'

DECLARE @Word TABLE(ID INT, Value VARCHAR(20))
INSERT INTO @Word
SELECT 1, 'dog'
UNION
SELECT 2, 'flowers'
UNION
SELECT 3, 'sea'
UNION
SELECT 4, 'moon'
UNION
SELECT 5, 'mountain'
UNION
SELECT 6, 'seashell'
UNION
SELECT 7, 'shell'
UNION
SELECT 8, 'concert'

DECLARE @WordToPhoto TABLE(ID INT, PhotoID INT, WordID INT)
INSERT INTO @WordToPhoto
SELECT 1, 1, 2
UNION
SELECT 2, 1, 4
UNION
SELECT 3, 2, 1
UNION
SELECT 4, 2, 3
UNION
SELECT 5, 2, 6
UNION
SELECT 6, 3, 1
UNION
SELECT 7, 3, 2

您正在搜索'doggy'和'flower'关键字的搜索:

DECLARE @Words TABLE (Word VARCHAR(20))
INSERT INTO @Words
SELECT 'doggy' UNION
SELECT 'flower'

如果您搜索了多个关键字,那么您可能需要一些评分系统。我的建议是总结每张照片的积分。 Point将使用此算法计算:


If Photo Keyword is the same as Search Keyword then 1 
(dog = dog)
Else If Photo Keyword is a Search Keyword with postfix then 0.75 
(dog LIKE doggy)
Else If Search Keyword is a Photo Keyword with postfix then 0.75 
(doggy LIKE dog) 
Else If Photo Keyword is a Search Keyword with prefix then 0.5 
(dog LIKE bulldog) 
Else If Search Keyword is a Photo Keyword with prefix then 0.5 
(hotdog LIKE dog) 
Else If Photo Keyword is a Search Keyword with prefix and postfix then 0.25 
(dog LIKE Snoopdogg) 
Else If Search Keyword is a Photo Keyword with prefix and postfix then 0.25 
(overdogged LIKE dog) 

点系数可能是其他的,这只是一个例子。

实现:

SELECT R.Rating, P.* FROM @Photo P
INNER JOIN
(
    SELECT PhotoID, SUM(W.Point) AS Rating 
    FROM @WordToPhoto WTP 
    INNER JOIN (
        SELECT W.ID, 
        CASE 
            WHEN (LOWER(WS.Word) = LOWER(W.Value)) THEN 1 
            WHEN (LOWER(WS.Word) LIKE LOWER(W.Value)+'%') 
            OR (LOWER(W.Value) LIKE LOWER(WS.Word)+'%') THEN 0.75 
            WHEN (LOWER(WS.Word) LIKE '%'+LOWER(W.Value)) 
            OR (LOWER(W.Value) LIKE '%'+LOWER(WS.Word))  THEN 0.5
            ELSE 0.25
            END AS Point
        FROM @Word W
        INNER JOIN @Words WS ON LOWER(WS.Word) LIKE '%'+LOWER(W.Value)+'%' 
                OR LOWER(W.Value) LIKE '%'+LOWER(WS.Word)+'%'
    ) AS W ON W.ID = WTP.WordID
    GROUP BY PhotoID
) AS R ON P.ID = R.PhotoID

ORDER BY R.Rating DESC

结果:

Rating ID      Name            Title           Description
1.50   3       garden.jpg      Garden          Garden
0.75   1       mountain.jpg    Mountain trip   Mountain trip
0.75   2       beach.jpg       On the beach    On the beach

答案 1 :(得分:1)

对于Postgres或MySQL,您可以查看Sphinx 用于

的全文搜索

http://www.sphinxsearch.com/

各种Web框架都有很好的适配器/插件。 例如,ThinkingSphinx在Ruby on Rails中非常出色

http://github.com/freelancing-god/thinking-sphinx

Sphinx支持您选择的字段的全文搜索, delta索引,并且很好地扩展。

答案 2 :(得分:1)

您需要决定多个关键字的连接方式。如果有人在搜索中键入“keyword1 keyword2”,他们是否正在寻找与同一张照片相关联的关键字(AND操作),或者他们是否正在寻找与同一张照片关联的关键字(或两者)(或者操作)。提供两者怎么样?那么“这个关键字而不是其他关键字”等等......

我不清楚WordID列提供了什么 - 除了占用磁盘空间。如果你有一个带有'WordID,Word'作为列的表,并且交叉引用表有'PhotoID,WordID'列,这就是一个合理的设计。另一个合理的设计有'PhotoID,Word'。拥有'WordID,PhotoID,Word'的表格并不是特别明智;它会工作,但WordID列实际上是未使用的。您需要对组合PhotoID,Word的唯一约束,以确保您没有在该表中重复。

鉴于您的@Words(临时)表,您可以执行此操作以获取AND选项:

SELECT P.PhotoID, P.Name, P.Title, P.Description
    FROM Photo P, Word2Photo W
    WHERE P.PhotoID = W.PhotoID
    GROUP BY P.PhotoID, P.Name, P.Title, P.Description
    HAVING COUNT(*) = (SELECT COUNT(*) FROM @Words L, Word2Photo M
                           WHERE M.Word = L.Word
                             AND M.PhotoID = P.PhotoID
                      )

确保Word2Photo表中的条目数与给定照片的@Words表中的条目数相同。它是一个相关的子查询;它效率不高但效果很好。有用的是,结构可以主要用于OR选项:

SELECT P.PhotoID, P.Name, P.Title, P.Description
    FROM Photo P, Word2Photo W
    WHERE P.PhotoID = W.PhotoID
    GROUP BY P.PhotoID, P.Name, P.Title, P.Description
    HAVING 1 <= (SELECT COUNT(*) FROM @Words L, Word2Photo M
                    WHERE M.Word = L.Word
                      AND M.PhotoID = P.PhotoID
                )

这会查找包含单词列表中至少一个单词的照片。

可能还有其他方法可以做到,但对称性很吸引人。显然,如果你进入更复杂的标准(混合AND和OR,或添加NOT),那么结构会发生变化。

买者

未经测试的代码。

答案 3 :(得分:1)

几年前我在我的网站上做过这个。我所做的是削减了SQL不擅长应用程序的所有东西。从记忆中,它就像是:

table photos (
    photoid        number unique indexed,
    name           varchar2,
    title          varchar2,
    description    varchar2,
    keywords       varchar2,
    ... etc
);

table photosearch (
    wordid      number indexed,  -- ID of word, more or less
    photoid     number,          -- ref photos.photoid
    context     number,          -- 9=title, 7=name, 5=desc, ..
    ... etc 
)

插入/更新照片时,基本算法为:

photoid = INSERT INTO PHOTOS VALUES (...)

foreach field in (name title description keywords) 
    int weight = getweight(field)
    foreach word in ( value(field) ) 
        # Discard useless words, e.g. "and, or, but, yes, ..."
        stem = word-stem-algorithm(word)
        key  = hash-to-number(stem)
        INSERT INTO PHOTOSEARCH VALUES 
            (key, photoid, weight)

通用搜索就像是:

keys [] = hash(stem(word)) foreach word in query

SELECT photoid, sum(context) FROM photosearch
 WHERE wordid IN keys[]
 GROUP BY photoid
 ORDER BY 2 DESC

使用context == unique_weight的技巧让我可以轻松地进行“字段包含单词”搜索(左边作为练习给读者;),并允许我通过改变字段的权重来“调整”结果顺序。 / p>

答案 4 :(得分:0)

你的意思并不完全清楚,但听起来就像你想要的那样:

SELECT /* some columns */
FROM @Words #w
INNER JOIN WORD2PHOTO wp ON wp.Word = #w.Word
INNER JOIN PHOTO p NO p.PhotoID = wp.PhotoID

重新标题和描述;好吧,你可以做一些涉及LIKE的kludgy,但作为替代方案,你为什么不简单地反汇编标题和描述(拆分空白/标点符号),并将它们放入WORD2PHOTO表中(用标记表示)表明它们来自标题/描述) - 然后变为:

SELECT /* some columns */
FROM @Words #w
INNER JOIN WORD2PHOTO wp
   ON wp.Word = #w.Word
   AND wp.Source IN ('K','T','D') -- keywords/title/description
INNER JOIN PHOTO p NO p.PhotoID = wp.PhotoID

只需包含不同的K / T / D组合以适应......

您只需要一个触发器,这样当您插入/更新标题/描述时,它会删除所有现有的T / D条目并替换为新的条目。