对于字典搜索,有没有更好的替代方法?

问题描述

以下代码可以快速简短地从句子的子集中识别句子是否属于某种语言。 对于每个句子,都会对字典进行扫描,并根据积极的命中结果来形成分数。

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上进行了排序)。
  • 确保您在term表中的Dictionary上有索引(以及后续步骤所需的适当语言等)-因为它将是关键查找表
  • 然后在term上的#SentenceWords表和Dictionary表之间进行内部联接

例如

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...