Sql 对于字典搜索,有没有更好的替代交叉连接的方法?

Sql 对于字典搜索,有没有更好的替代交叉连接的方法?,sql,sql-server,tsql,sql-server-2008,cross-join,Sql,Sql Server,Tsql,Sql Server 2008,Cross Join,下面的代码是一个快速而简短的飞跃,可以从字典的子集中识别一个句子是否属于任何语言。 对每一个句子,字典都会被扫描,并根据正确的点击率形成一个分数 CREATE TABLE [dbo].[Sentences]( [sentenceId] [int] IDENTITY(1,1) NOT NULL, [sentence] [nvarchar](1000) NULL ) ON [PRIMARY] GO CREATE TABLE [dbo].[Dictionary]( [id]

下面的代码是一个快速而简短的飞跃,可以从字典的子集中识别一个句子是否属于任何语言。 对每一个句子,字典都会被扫描,并根据正确的点击率形成一个分数

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,1) NOT NULL,
    [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#语句词(term varchar(20),sentenceId int)
  • <>你也可以考虑在那个临时表上创建索引等,但是它不是100%个必要的。如果是我,我会将带有计数的不同单词放入以term开头的主键表中,例如,
    CREATE table#SentenceWords(term varchar(20)、sentenceId、numtimesappered int、主键(term、sentenceId))
    。将它们放入此表将需要额外的处理,但会减少下一步的处理(并且可能允许合并联接,因为它已经在主键中的
    项上排序了)
    
  • 确保在
    字典
    表中有
    术语
    (以及下一步所需的适当语言等)的索引,因为它将是键查找表
  • 然后在
    term
e、 g

并且做任何你需要的计数/求和/等(例如,如果你使用上述方法,在NumTimesAppears上)

注意-你的句子是
nvarchar
,术语是
varchar
。如果可能,请使它们一致

  • 为了准确
  • 还可以停止可能妨碍索引使用的隐式转换问题
  • 鉴于您使用的是不同的语言,我建议您使用nvarchar
我相信上面的方法应该可以很好地工作——这里的关键是确保字典按照术语进行排序(例如,有索引),这意味着它可以进行有效的查找/连接

我认为如果你能让上面的索引工作起来,这是没有必要的,但是为了进一步的改进,你可以做如下的事情

  • 有单独的字典。。。一个用于通用语言,一个用于不太通用的语言。只有在第一本词典中未找到满意的解决方案时,才转到第二本词典
  • 确定关键术语并首先检查这些术语。只有在找不到的情况下,才转到完整的句子
    • 我建议

      • 首先在临时表格中将句子拆分为单个单词,例如:。,
        CREATE TABLE#语句词(term varchar(20),sentenceId int)
      • <>你也可以考虑在那个临时表上创建索引等,但是它不是100%个必要的。如果是我,我会将带有计数的不同单词放入以term开头的主键表中,例如,
        CREATE table#SentenceWords(term varchar(20)、sentenceId、numtimesappered int、主键(term、sentenceId))
        。将它们放入此表将需要额外的处理,但会减少下一步的处理(并且可能允许合并联接,因为它已经在主键中的
        项上排序了)
        
      • 确保在
        字典
        表中有
        术语
        (以及下一步所需的适当语言等)的索引,因为它将是键查找表
      • 然后在
        term
      e、 g

      并且做任何你需要的计数/求和/等(例如,如果你使用上述方法,在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
          
          
          将@xml声明为xml
          将@sid声明为INT
          选择[sentenceId]作为[id],CAST(“”+REPLACE(CAST(LOWER(RTRIM([句子]))作为VARCHAR(MAX)),“”,“,”+”作为XML)作为[句子]
          从[dbo]转换成#xml句子。[句子]
          而(从#xmlstations中选择COUNT(*)大于0
          开始
          SET@sid=(从#xmlstations中选择前1个[id]
          SET@xml=(从#xmlstations中选择前1个[句子])
          从#xml句子中删除顶部(1);
          选择@sid
          来自@xml.nodes('/root/x')f([score])
          左连接[dbo]。[字典]
          在[term]=f[score]上。值('.','VARCHAR(MAX)'
          具有10*SUM(符号(ISNULL(LEN([term]),0))/(计数(f.[score]。值('.','VARCHAR(MAX)'))+1)>1
          结束
          
          这里是进一步研究语言识别问题的一步。虽然代码对我的口味来说有点太麻烦了,但它的速度足够快
          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