问题描述
以下代码可以快速简短地从句子的子集中识别句子是否属于某种语言。 对于每个句子,都会对字典进行扫描,并根据积极的命中结果来形成分数。
CREATE TABLE [dbo].[Sentences](
[sentenceId] [int] IDENTITY(1,1) NOT NULL,[sentence] [nvarchar](1000) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Dictionary](
[id] [int] IDENTITY(1,[term] [varchar](20) NOT NULL,[meaning] [varchar](1000) NOT NULL
) ON [PRIMARY]
GO
(populate tables)
GO
WITH Test(id,score) AS (
SELECT sentenceId,100 * SUM(SIGN(CHARINDEX(' ' + term + ' ',LOWER(sentence)))) / MAX(LEN(sentence) + 1)
FROM dbo.Sentences,dbo.Dictionary
GROUP BY sentenceId
)
SELECT COUNT(*)
FROM dbo.Sentences
JOIN Test ON id = sentenceId
WHERE score > 1
GO
根据结果,字典表的最佳大小被确定为大约1750个词。但是,执行时间成本限制了该解决方案在大型表中的实用性。
1000 x 175 1 sentences,2s
5000 x 175 11 sentences,7s
10000 x 175 17 sentences,13s
1000 x 350 6 sentences,4s
5000 x 350 45 sentences,15s
10000 x 350 74 sentences,26s
1000 x 1750 29 sentences,22s
5000 x 1750 178 sentences,63s
10000 x 1750 312 sentences,119s
1000 x 3500 29 sentences,45s
5000 x 3500 179 sentences,120s
10000 x 3500 315 sentences,233s
欢迎改进。例如,一旦分数被确定为> 1,就无需完全扫描字典表。
解决方法
我建议
- 首先在临时表中将句子拆分成单个单词,例如,
CREATE TABLE #SentenceWords (term varchar(20),sentenceId int)
- 您也可以考虑在该临时表上创建索引等,但这不是100%必要的。如果是我,我会用主键(例如
CREATE TABLE #SentenceWords (term varchar(20),sentenceId,NumTimesAppeared int,PRIMARY KEY (term,sentenceId))
)将带有计数的不同单词放入表中。 将会进行额外的处理,使它们进入该表,但会减少下一步的处理(并可能允许合并联接,因为它已经在主键的 - 确保您在
term
表中的Dictionary
上有索引(以及后续步骤所需的适当语言等)-因为它将是关键查找表 - 然后在
term
上的#SentenceWords表和Dictionary表之间进行内部联接
term
上进行了排序)。
例如
SELECT sw.sentenceId,d.id
FROM #SentenceWords AS sw
INNER JOIN Dictionary AS d ON sw.term = d.term
并执行所需的任何计数/总和/等操作(例如,如果使用上述方法,则在NumTimesAppears上显示)。
请注意-您的句子为nvarchar
,术语为varchar
。请尽可能保持一致
- 为了准确性
- 还停止了隐式转换问题,该问题可能会妨碍索引的使用
- 如果您使用不同的语言,建议您使用nvarchar。
我相信以上代码应该能很好地工作-这里的关键是确保字典按术语排序(例如,具有索引),这意味着它可以进行高效的查找/连接。
如果您的索引在上面工作,我认为没有必要,但是对于进一步的改进,您可以执行类似的操作
- 有单独的词典...一本用于通用语言,一本用于不常见的语言。如果在第一本字典中找不到满意的解决方案,则仅转到第二本字典。
- 确定关键术语并首先检查。仅在找不到这些单词的情况下,转到完整的句子。
这是进一步解决语言识别问题的步骤。虽然我觉得代码太乱了,但它的速度足够快,可以实际使用,而且发现它更准确。
1000 x 3500 37 sentences,6s
5000 x 3500 194 sentences,28s
10000 x 3500 341 sentences,54s
随后是代码,为清楚起见,省略了用于从句子中提取所有术语的标记化功能。
DECLARE @xml AS XML
DECLARE @sid AS INT
SELECT [sentenceId] AS [id],CAST('<root><x>' + REPLACE(CAST(LOWER(RTRIM([sentence])) AS VARCHAR(MAX)),' ','</x><x>') + '</x></root>' AS XML) AS [sentence]
INTO #XMLSentences FROM [dbo].[Sentences]
WHILE (SELECT COUNT(*) FROM #XMLSentences) > 0
BEGIN
SET @sid = (SELECT TOP 1 [id] FROM #XMLSentences)
SET @xml = (SELECT TOP 1 [sentence] FROM #XMLSentences)
DELETE TOP (1) FROM #XMLSentences;
SELECT @sid
FROM @xml.nodes('/root/x') f([score])
LEFT JOIN [dbo].[Dictionary]
ON [term] = f.[score].value('.','VARCHAR(MAX)')
HAVING 10 * SUM(SIGN(ISNULL(LEN([term]),0))) / (COUNT(f.[score].value('.','VARCHAR(MAX)')) + 1) > 1
END