2010-11-02 73 views
1

我正在嘗試使用mysql構建一個小型練習搜索引擎。需要幫助用於排名搜索結果的SQL

每個練習可以有任意數量的搜索標籤。

這裏是我的數據結構:

TABLE exercises 
    ID 
    title 

TABLE searchtags 
    ID 
    title 

TABLE exerciseSearchtags 
    exerciseID -> exercises.ID 
    searchtagID -> searchtags.ID 

...其中exerciseSearchtags是一個多對多的連接表表達練習和searchtags之間的關係。

搜索引擎接受未知數量的用戶輸入關鍵字。

我想根據關鍵字/ searchtag匹配的數量對搜索結果進行排名。

這是我目前用來選擇練習的sql。動態生成CASE規則和WHERE規則,每個關鍵字一個。例如,如果用戶輸入3個關鍵字,則會有3個CASE規則和3個WHERE規則。

SELECT 
     exercises.ID AS ID, 
     exercises.title AS title, 
     (
      (CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END)+ 
      (CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END)+ 
      ...etc... 
      (CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END) 
     ) AS relevance 

    FROM 
     exercises 

    LEFT JOIN exerciseSearchtags 
     ON exerciseSearchtags.exerciseID = exercises.ID 

    LEFT JOIN searchtags 
     ON searchtags.ID = exerciseSearchtags.searchtagID 

    WHERE 
     searchtags.title LIKE CONCAT('%',?,'%') OR 
     searchtags.title LIKE CONCAT('%',?,'%') OR 
     ...etc... 
     searchtags.title LIKE CONCAT('%',?,'%') 

    GROUP BY 
     exercises.ID     

    ORDER BY 
     relevance DESC 

幾乎作品。但是結果並沒有按照我預期的順序排列。

爲什麼會出現這種情況,我最好猜測的是相關性分數是在exercise.ID分組之前進行計算的。因此,如果左連接導致特定練習在結果集中出現10次,而另一個練習出現4次,則第一個練習可能會獲得更高的相關分數,即使它可能沒有更多關鍵字/ searchtag匹配。

有沒有人有任何建議/建議如何防止發生/解決這個問題?

(提前)感謝您的幫助。

回答

0

分而治之。不要試圖在一個聲明中做所有事情,而是嘗試將問題分解爲更小的部分。例如,首先創建一個包含至少一個搜索標記的所有練習的臨時表。然後進行第二階段,以便在臨時表中對每個練習進行排名。最後選擇按排名排序的結果。

0

我只是做了類似的東西爲MSSQL不是MySQL的...所以這可能是不相關的所有,但它值得一試:)

我不得不把機箱的作爲order by子句的一部分得到它正確地如把它撿起來:

 
ORDER BY 
    CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END + 
    CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END + 
    ...etc... 
    CASE WHEN searchtags.title LIKE CONCAT('%',?,'%') THEN 1 ELSE 0 END DESC 

雖然在SELECT也讓他們這樣我就可以輸出頁面上的相關性(的要求)

無論哪種方式,祝你好運吧!

+0

感謝您的建議。我試圖將CASE規則硬編碼到ORDER BY語句中,但不幸的是它並沒有改變結果的順序。所以我想這也是計算之前的行分組在mysql – Travis 2010-11-02 06:18:06

+0

好啊;一個恥辱,我檢查了我的代碼,以防萬一有其他事情發生時我做了它,但那是它。祝你好運! :) – 2010-11-02 06:25:09

1

我發現了上述問題的工作解決方案,並在此處發佈,以防其他人遇到類似問題。

解決方案是使用子選擇而不是case語句。以上是上述代碼的修改。 (我不知道這是否是最好的或最有效的解決方案,但它已經爲我暫時解決了麻煩,並且似乎能夠合理快速地返回搜索結果。)

SELECT 
    exercises.ID AS ID, 
    exercises.title AS title, 
    (
     (
      SELECT COUNT(1) 
      FROM searchtags 
      LEFT JOIN exerciseSearchtags 
      ON exerciseSearchtags.searchtagID = searchtags.ID 
      WHERE searchtags.title LIKE CONCAT('%',?,'%') 
      AND exerciseSearchtags.exerciseID = exercises.ID 
     )+ 
     (
      SELECT COUNT(1) 
      FROM searchtags 
      LEFT JOIN exerciseSearchtags 
      ON exerciseSearchtags.searchtagID = searchtags.ID 
      WHERE searchtags.title LIKE CONCAT('%',?,'%') 
      AND exerciseSearchtags.exerciseID = exercises.ID 
     )+ 
     ...etc... 
     (
      SELECT COUNT(1) 
      FROM searchtags 
      LEFT JOIN exerciseSearchtags 
      ON exerciseSearchtags.searchtagID = searchtags.ID 
      WHERE searchtags.title LIKE CONCAT('%',?,'%') 
      AND exerciseSearchtags.exerciseID = exercises.ID 
     ) 
    ) AS relevance 

FROM 
    exercises 

LEFT JOIN exerciseSearchtags 
    ON exerciseSearchtags.exerciseID = exercises.ID 

LEFT JOIN searchtags 
    ON searchtags.ID = exerciseSearchtags.searchtagID 

WHERE 
    searchtags.title LIKE CONCAT('%',?,'%') OR 
    searchtags.title LIKE CONCAT('%',?,'%') OR 
    ...etc... 
    searchtags.title LIKE CONCAT('%',?,'%') 

GROUP BY 
    exercises.ID     

ORDER BY 
    relevance DESC