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