bro*_*ozo 7 sql-server full-text-search sql-server-2008-r2
我在尝试在 SQL Server 2008 R2 中实现 BM25 算法时遇到了问题。我知道 SQL Server 包含全文搜索选项,它已经实现了 BM25 的变体,但我想做一些参数调整测试,并且由于 FTS 过程是不可编辑的(据我所知),我我决定自己实现它。
我有两个表,TF(词频)和 DF(文档频率),结构如下:
TF
*注:权重列表示该词的重要性(通常为1)
ID | Term | DocumentID | Count | TermID | Weight*
Run Code Online (Sandbox Code Playgroud)
DF
ID | Term | Count
Run Code Online (Sandbox Code Playgroud)
TF 表包含了词条和文档之间的关系;也就是说,该词在文档中的出现频率。DF 表包含有关有多少文档包含一个术语的信息。可以使用 DF.ID 和 TF.TermID 链接这两个表。使用这两个表,我现在想根据维基百科文章中的公式计算两个文档(一个文档充当查询)之间的 BM25 相似度值。表 TF 和 DF 分别转换为函数 f(q, D) 和 n(q):


我希望结果采用以下格式:
DocumentA_ID | DocumentB_ID | BM25_Value
Run Code Online (Sandbox Code Playgroud)
这是我到目前为止的一些代码:
DECLARE @N FLOAT;
DECLARE @AVGDL FLOAT;
DECLARE @K1 FLOAT;
DECLARE @B FLOAT;
SET @K1 = 1.2;
SET @B = 0.75;
-- number of all documents
SELECT @N = COUNT(DISTINCT DocumentID) FROM TF;
-- average document length (in words)
SELECT @AVGDL = AVG(DocumentLength) FROM (SELECT DocumentID, SUM(TF.Count) AS DocumentLength FROM TF WHERE Weight = 3 GROUP BY DocumentID) A;
-- BM25 implementation
SELECT D.DocumentID AS DocumentA,
Q.DocumentID AS DocumentB,
*,
-- need help here (SUM or something ...)
LOG((@N - DF.Count + 0.5)/(DF.Count + 0.5)) AS IDF
FROM TF AS D
INNER JOIN TF AS Q ON D.Term = Q.Term
INNER JOIN DF ON D.TermID = DF.ID
WHERE D.DocumentID <> Q.DocumentID
Run Code Online (Sandbox Code Playgroud)
我在最后一节(BM25 实现)中构建查询以获取所需的结果格式时遇到问题。任何帮助将不胜感激。
经过几天的摆弄,我终于设法完成了这项工作。这是我最终得到的代码,打包到一个存储过程中。为此,我添加了另一个表,其中仅包含文档 ID 及其长度(以字为单位)。
ALTER PROCEDURE [dbo].[BuildIndexBM25]
-- default parameters K1=> [1.2 - 2.0], B => [0.0 - 1.0], Weight => 3 (e.g. titles only)
@K1 FLOAT = 1.2,
@B FLOAT = 0.75,
@Weight FLOAT = 3
AS
BEGIN
SET NOCOUNT ON;
DECLARE @N FLOAT;
DECLARE @AVGDL FLOAT;
-- number of all documents
SELECT @N = COUNT(DISTINCT DocumentID) FROM TF;
-- average document length (in words)
SELECT @AVGDL = AVG(Length) FROM DocumentLength;
-- BM25 implementation
-- result set: | DocumentA | DocumentB | BM25 |
SELECT
DL.ID AS DocumentA,
BM.DocumentID AS DocumentB,
BM.BM25 AS BM25
FROM (
SELECT ID FROM DocumentLength
) DL
CROSS APPLY (
SELECT
Q.DocumentID,
SUM(LOG((@N - X.Count + 0.5) / (X.Count + 0.5)) * (Q.Count * (@K1 + 1)) / (Q.Count + @K1 * (1 - @B + (@B * L.Length / @AVGDL)))) AS BM25
FROM TF D, TF Q, DF X, DocumentLength L
WHERE D.TermID = Q.TermID
AND D.DocumentID = DL.ID
AND Q.TermID = X.ID
AND D.DocumentID = L.ID
AND Q.Weight = @Weight
AND D.Weight = @Weight
GROUP BY Q.DocumentID
) BM
WHERE DL.ID != BM.DocumentID
END
Run Code Online (Sandbox Code Playgroud)
我希望这个答案可以帮助任何想要自己实现全文搜索算法的人。SQL Server 2008 R2 中的默认算法与此实现只有细微的差别。