You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在SQL Server/Azure SQL中获取单词的词形变化形式并按词形组聚合全文索引关键词统计?

如何在SQL Server/Azure SQL中获取单词的词形变化形式并按词形组聚合全文索引关键词统计?

这个需求我之前做全文索引分析的时候也碰到过,确实SQL Server没有直接给一个开箱即用的函数来返回某个词的所有屈折形式,但咱们可以通过几个实用的技巧实现,而且能完美完成你要的按屈折组聚合统计的目标,一步步来:


一、先搞定:如何获取单个单词的所有屈折形式?

SQL Server的全文引擎有个隐藏的“神器”——sys.dm_fts_parser动态管理函数,它能调用全文分析器解析任意查询字符串,包括屈折形式的查询。用它就能轻松拿到某个词的所有屈折变化。

比如要获取“swim”的所有屈折形式,直接执行:

SELECT DISTINCT display_term
FROM sys.dm_fts_parser('FORMSOF(INFLECTIONAL, "swim")', 1033, NULL, 0)
-- 过滤掉英语噪音词(比如the、a这类无意义的词)
WHERE display_term NOT IN (SELECT word FROM sys.fulltext_stopwords WHERE language_id = 1033)

执行后会返回你预期的结果:swimswamswumswimming

参数小科普:

  • 1033是英语的LCID(语言代码),如果你的全文索引用的是其他语言,比如中文换成2052,可以查sys.fulltext_languages看所有支持的语言;
  • 第三个参数填NULL表示不启用同义词库,要是你有自定义同义词库可以传它的ID;
  • 第四个参数0表示不忽略噪音词,方便我们手动过滤掉不需要的词。

二、核心目标:按屈折组聚合全文索引的统计数

你要把sys.dm_fts_index_keywords里同属一个屈折组的词的document_count汇总,这个可以通过临时表+关联分析来实现,步骤很清晰:

步骤1:导出全文索引的关键词数据

先把全文索引里的关键词和对应文档数导出到临时表,方便后续操作:

-- 记得替换成你的带全文索引的表名
DECLARE @TargetTable NVARCHAR(128) = 'YourFulltextIndexedTable'

SELECT 
    display_term,
    document_count
INTO #FtsKeywords
FROM sys.dm_fts_index_keywords(DB_ID(), OBJECT_ID(@TargetTable))
WHERE 
    display_term NOT LIKE '##%' -- 排除系统内置的特殊二进制词
    AND document_count > 0 -- 去掉没有对应文档的无效词

步骤2:生成每个词的屈折组映射

通过CROSS APPLY调用sys.dm_fts_parser,为每个词匹配它所属的屈折组里的所有词,而且只保留我们索引里实际存在的词(避免出现索引里没有的无效词):

SELECT 
    k.display_term AS source_term,
    p.display_term AS inflectional_term
INTO #InflectionalGroups
FROM #FtsKeywords k
CROSS APPLY sys.dm_fts_parser(
    -- 替换词里的双引号,避免解析出错
    'FORMSOF(INFLECTIONAL, "' + REPLACE(k.display_term, '"', '""') + '")', 
    1033, 
    NULL, 
    0
) p
WHERE 
    p.display_term IN (SELECT display_term FROM #FtsKeywords)
    AND p.display_term NOT IN (SELECT word FROM sys.fulltext_stopwords WHERE language_id = 1033)

步骤3:按屈折组聚合统计

现在我们要为每个屈折组选一个“代表词”(比如组里字典序最小的词),然后把同组所有词的文档数加起来:

WITH GroupedTerms AS (
    SELECT 
        ig.source_term,
        ig.inflectional_term,
        -- 选组里字典序最小的词作为组名,也可以换成你喜欢的其他规则
        MIN(ig.inflectional_term) OVER (PARTITION BY ig.source_term) AS group_representative
    FROM #InflectionalGroups ig
)
SELECT 
    group_representative AS display_term_group,
    SUM(k.document_count) AS total_document_count
FROM GroupedTerms gt
JOIN #FtsKeywords k ON gt.source_term = k.display_term
GROUP BY group_representative
ORDER BY total_document_count DESC

执行后你会得到类似这样的结果:

display_term_grouptotal_document_count
limit4062
limited1396994
limitation1135

(小提醒:这里limitlimited可能分属不同组,因为英语的词干分析器会区分动词和形容词的屈折形式,如果需要把派生形式比如limitlimitation也聚合,就得靠自定义同义词库来配置了)

最后别忘了清理临时表

DROP TABLE IF EXISTS #FtsKeywords
DROP TABLE IF EXISTS #InflectionalGroups

三、几个关键注意事项

  1. 语言要匹配:一定要保证用的LCID和你的全文索引语言一致,不然词干分析结果会出错,比如你用了中文全文索引却传1033(英语),结果肯定不对;
  2. 性能优化:如果你的全文索引特别大,临时表会占不少资源,可以先过滤掉低频词(比如document_count < 10),或者分批处理;
  3. 屈折形式 vs 派生形式:屈折形式是语法变化(比如动词时态、名词单复数),派生形式是加前缀后缀生成的新词(比如swimswimmer),全文引擎不会自动把派生形式归为同一组,要聚合派生形式得自己做同义词库;
  4. 噪音词过滤:一定要记得过滤噪音词,不然统计结果会被thea这类无意义的词占满。

这样就完全实现了你的需求,既能单独查某个词的屈折形式,又能按屈折组聚合统计全文索引的关键词数据啦!

火山引擎 最新活动