Small. Fast. Reliable.
Choose any three.
Spellfix1虚拟表

1.概述

该spellfix1虚拟表可用于搜索大词汇以查找紧密匹配项。例如,spellfix1可用于建议对拼写错误的单词的更正。或者,它可以与FTS4一起使用,以使用可能拼写错误的单词进行全文搜索。

spellfix1虚拟表的实现保存在其他扩展文件夹的SQLite源树中,尤其是在文件 ext / misc / spellfix1.c中。spellfix1虚拟表未包含在SQLite合并中 ,也不是任何标准SQLite构建的一部分。这是一个可加载的扩展

加载了spellfix1扩展名后,将按以下方式创建spellfix1虚拟表的实例:

使用spellfix1创建虚拟表演示;

“ spellfix1”术语是spellfix模块的名称,必须如图所示输入。“演示”一词是您将创建的虚拟表的名称,可以对其进行更改以适合您的应用程序的需求。虚拟表最初是空的。为了使虚拟表有用,您需要用词汇表填充它。假设您在名为“ big_vocabulary”的表中有一个单词列表。然后执行以下操作:

插入演示(单词)从big_vocabulary中选择单词;

如果打算将此虚拟表与FTS4 表配合使用(用于对搜索词进行拼写更正),则可以使用fts4aux表提取词汇表:

插入demo(word)SELECT术语FROM search_aux WHERE col ='*';

您还可以为虚拟表的每个单词提供一个“等级”。“等级”是对该词的普遍程度的估计。数字越大,表示该词越常见。如果在填充表格时忽略等级,则假设等级为1。但是,如果您具有排名信息,则可以提供它,并且虚拟表会稍微偏向于选择更常用的术语。要从fts4aux表“ search_aux”填充等级,请执行以下操作:

插入演示(word,rank)
   SELECT术语,文档来自search_aux WHERE col ='*';

若要查询虚拟表,请在WHERE子句中包含MATCH运算符。例如:

从演示中选择单词,在其中匹配单词“ kennasaw”;

使用美国地名的数据集(源自 http://geonames.usgs.gov/domestic/download_data.htm),上面的查询返回20个结果,开头为:

Kennesaw
基诺沙
Kenesaw
永永
基纳克

如果将字符“ *”附加到模式的末尾,则会执行前缀搜索。例如:

从演示中选择单词,其中单词MATCH'kennes *';

产生20个结果,开始于:

Kennesaw
肯尼斯顿
肯尼森
肯尼
基恩斯
基恩

2.搜索优化

默认情况下,spellfix1表返回的结果不超过20个。(如果匹配次数较少,则返回的值可能少于20。)您可以通过在查询的WHERE子句中添加“ top = N”项来更改返回行数的上限,其中N是新的最大值。例如,要查看5个最佳匹配:

从演示中选择单词,在其中匹配MATCH'kennes *'并且top = 5;

spellfix1虚拟表中的每个条目都与一种特定的语言相关联,该语言由整数“ langid”列标识。默认的langid为0,如果没有其他动作,则整个词汇表是0语言的一部分。但是,如果您的应用程序需要使用多种语言进行操作,则可以在填充表时通过指定langid字段为每种语言指定不同的词汇表项。例如:

INSERT INTO demo(word,langid)SELECT word,0 FROM en_vocabulary;
INSERT INTO demo(word,langid)SELECT word,1 FROM de_vocabulary;
INSERT INTO demo(word,langid)SELECT word,2 FROM fr_vocabulary;
插入演示(word,langid)SELECT单词,3 FROM ru_vocabulary;
INSERT INTO demo(word,langid)SELECT word,4 FROM cn_vocabulary;

用多种语言的项目填充虚拟表后,在查询的WHERE子句中使用“ langid = N”术语指定感兴趣的语言:

从演示中选择单词,其中单词MATCH'hildes *'并且langid = 1;

请注意,如果未在WHERE子句中包含“ langid = N”,则搜索将针对语言0(在上例中为英语)。所有spellfix1搜索均针对单个语言ID。无法一次搜索所有语言。

3.虚拟表详细信息

spellfix1虚拟表中的每一行都有一个唯一的rowid,其中包含七个列以及五个额外的隐藏列。列如下:

行号

与表中每个词汇表项目相关联的唯一整数。可以将其用作数据库中其他表上的外键。

单词

与模式匹配的单词的文本。单词和模式都可以包含unicode字符,并且可以大小写混合。

这是单词的等级,如原始INSERT语句中所指定。

距离

这是从样式到单词的编辑距离或Levenshtein距离。

乏味的

这是单词的语言ID。所有查询均针对单个语言ID,默认为0。对于任何给定查询,此值在所有行上均相同。

分数

分数是等级和距离的组合。这个想法是分数越低越好。虚拟表尝试查找分数最低的单词,并且默认情况下(除非被ORDER BY覆盖)以分数递增的顺序返回结果。

Matchlen

在前缀搜索中,matchlen是字符串中与前缀匹配的字符数。对于非前缀搜索,这与length(word)相同。

电话哈希

此列显示用于限制搜索的语音哈希前缀。对于任何给定的查询,此列的每一行都应该相同。该信息可用于诊断目的,通常在实际应用中不被认为有用。

最佳

(隐藏)对于任何查询,此值在所有行上均相同。它是一个整数,它是将输出的最大行数。输出的实际行数可能小于此数目,但永远不会大于此数目。top的默认值为20,但是可以通过在查询的WHERE子句中包含形式为“ top = N”的术语来为每个查询更改。

范围

(隐藏)对于任何查询,此值在所有行上均相同。范围是衡量虚拟表查找匹配单词的范围的度量。较小的范围值会导致更广泛的搜索。范围通常是自动选择的,上限为4。应用程序可以通过在查询的WHERE子句中包含形式为“ scope = N”的术语来更改范围。扩大范围将使查询运行更快,但会减少可能的更正。

srchcnt

(隐藏)对于任何查询,此值在所有行上均相同。该值是一个整数,该整数是使用编辑距离算法查找最终显示的最高匹配项所检查的单词数。此值仅用于诊断。

听起来好像

(隐藏)在插入词汇条目时,可以将此字段设置为与单词听起来相似的拼写。有关详细信息,请参见下面的“处理异常和困难的飞溅”部分。

命令

(隐藏)“命令”列的值始终为NULL。但是,应用程序可以在“命令”列中插入特殊字符串,以便在spellfix1虚拟表中引起某些行为。例如,将字符串“ reset”插入“命令”列将使虚拟表重新读取其编辑距离权重(如果有)。

4.算法

spellfix1虚拟表将创建一个名为“%_vocab”的影子表(其中%被虚拟表的名称替换;例如:“ demo_vocab”代表“ demo”虚拟表)。影子表包含以下列:

ID

唯一ID(INTEGER PRIMARY KEY)

词的等级。

乏味的

此项的语言ID。

单词

词汇词的原始UTF8文本

11

该单词被音译为小写ASCII。有一个从非ASCII字符到ASCII的映射的标准表。例如:“æ”->“ ae”,“þ”->“ th”,“ß”->“ ss”,“á”->“ a”,...辅助功能spellfix1_translit(X)将执行非ASCII到ASCII的映射。内置的lower(X)函数将转换为小写字母。因此:k1 = Lower(spellfix1_translit(word))。如果单词已经是全小写的ASCII,则k1列将包含NULL。这减少了%_vocab表的存储要求,并帮助spellfix运行得更快。因此,使用小写ASCII词汇表填充尽可能多的拼写修正表是有利的。

22

该字段包含从拼合(k1,word)派生的语音代码。具有相似声音的字母被映射到相同的符号中。例如,所有元音和元音簇成为单个符号“ A”。并且字母“ p”,“ b”,“ f”和“ v”都变为“ B”。所有的鼻音都表示为“ N”。依此类推。映射基于Soundex,Metaphone和其他长期存在的语音匹配系统中的想法。该密钥可以由功能spellfix1_phonehash(X)生成。因此:k2 = spellfix1_phonehash(coalesce(k1,word))

还有一个用于计算图案和单词之间的Wagner编辑距离或Levenshtein距离的功能。此函数显示为spellfix1_editdist(X,Y)。编辑距离函数返回将X转换为Y的“成本”。某些转换的成本高于其他转换。例如,将一个元音更改为另一个元音是相对便宜的,因为将常数加倍,或者省略了双常数的第二个字符。其他改造或更昂贵。这个想法是,编辑距离函数对于相似的单词返回较低的成本,而对于相距较远的单词返回较高的成本。在此实现中,任何单字符编辑(删除,插入或替换)的最大成本为100,而某些编辑(例如转换元音)的成本较低。

比较的“分数”是图案和单词之间的编辑距离,可通过单词等级的以2为底的对数向下调整。例如,距离为100但排名为1000的比赛得分为122(= 100-log2(1000)+ 32),而距离为100且排名为1的比赛得分为131(100-log2( 1)+ 32)。(注意:常数32会添加到每个分数中,以防止在编辑距离为零的情况下变为负数。)通过这种方式,经常使用的单词会获得较低的费用,这往往会将其移到列表的顶部。替代拼写。

拼写校正器的直接实现是将搜索词与词汇表中的每个单词进行比较,然后选择得分最低的20个单词。但是,词汇表中通常会有成千上万个单词,因此这种方法不够快。

假设要进行拼写校正的术语为X。为了限制搜索空间,X的等效项转换为类似k2的键:

   键= spellfix1_phonehash(下(spellfix1_translit(X)))

然后,此键仅限于“范围”字符。默认范围值是4,但是可以使用WHERE子句中的“ scope = N”术语指定替代范围。密钥被截断后,将对词汇表中具有以缩写密钥开头的k2值的每个术语进行编辑距离。

例如,假设输入单词是“ Paskagula”。语音键为“ BACACALA”,然后将其截断为4个字符“ BACA”。然后,在k2值以BACA开头的4980个词表(总共272,597个词表)中运行编辑距离,从而产生“ Pascagoula”作为最佳匹配。

仅搜索具有匹配语言限制的词汇表术语。因此,同一表可以包含来自多种语言的条目,并且仅使用所请求的语言。默认语言区域为0。

5.可配置的编辑距离

与固定权内置瓦格纳编辑距离函数可以通过更换editdist3()与应用程序定义的权重,并支持unicode的,通过指定“edit_cost_table =编辑距离函数TABLENAME ”参数到spellfix1模块当虚拟表已创建。例如:

使用spellfix1(edit_cost_table = APPCOST)创建虚拟表demo2

通过在虚拟表的“命令”列中插入适当的字符串,还可以在运行时选择或取消选择editdist3()编辑距离函数:

插入demo2(命令)VALUES('edit_cost_table = APPCOST');

在上面的示例中,将询问APPCOST表以找到编辑距离系数。spellfix1模块名称中存在“ edit_cost_table =“参数,这导致使用editdist3()代替内置的编辑距离功能。如果APPCOST为空字符串,则使用内置的Wagner编辑距离功能。

通常,将编辑距离系数从APPCOST表中读取一次,然后存储在内存中。因此,对APPCOST表的运行时更改通常不会影响编辑距离结果。但是,在虚拟表的“命令”列中插入特殊字符串“重置”会使编辑距离系数重新读取APPCOST表。因此,当对APPCOST表进行更改时,应用程序应运行类似于以下内容的SQL语句:

插入demo2(command)VALUES(“ reset”);

6.处理异常和困难的拼写

上面的算法在大多数情况下效果很好,但也有例外。这些异常可以通过使用“ soundslike”列在虚拟表中添加其他条目来处理。

例如,许多希腊起源的单词都以字母“ ps”开头,其中“ p”是无声的。例如:诗篇,化名,牛皮癣,精神病。在另一个示例中,许多苏格兰姓氏都可以用首字母“ Mac”或“ Mc”拼写。因此,“ MacKay”和“ McKay”的发音相同。

通过在虚拟表中为同一单词添加其他条目,然后在“类似声音”列中添加其他拼写,可以为未按发音拼写的单词提供调节。例如,“诗篇”的规范条目应为:

  插入演示(word)VALUES('psalm');

为了增强将“ salm”的拼写更正为“ psalm”的能力,请添加以下内容:

  插入演示(word,soundslike)VALUES('psalm','salm');

只要每个条目具有不同的听起来值,就可以为同一个单词创建多个条目。请注意,如果未指定类似声音的值,则类似声音默认为单词本身。

下面列出了在某些情况下可能需要添加其他类似声音的条目的情况。具体条目将取决于应用程序和目标语言。

7.辅助功能

实现spellfix1虚拟表的源代码模块还实现了一些SQL功能,这些功能可能对使用spellfix1的应用程序或在开发使用spellfix1的应用程序时进行测试或诊断工作很有用。以下辅助功能可用:

editdist3(P,W)
editdist3(P,W,L)
editdist3(T)

这些例程可直接访问Wagner编辑距离功能的版本,该功能允许应用程序定义编辑权重。此函数的前两种形式将模式P与单词W进行比较,并返回编辑距离。在第一个函数中,假定langid为0,在第二个函数中,lan​​gid由L参数给出。此函数的第三种形式从T命名的表中重新加载编辑距离系数。

spellfix1_editdist(P,W)

该例程提供对使用默认的固定成本的内置Wagner编辑距离功能的访问。返回的值是将W转换为P所需的编辑距离。

spellfix1_phonehash(X)

此例程构造纯ascii输入单词X的语音哈希,并返回该哈希。该例程由spellfix1内部使用,以便将影子表的K1列转换为K2列。

spellfix1_scriptcode(X)

给定输入字符串X,此例程将尝试确定该输入的主要脚本,并返回该脚本的ISO-15924数字代码。当前实现可理解以下脚本:
  • 215-拉丁
  • 220-西里尔文
  • 200-希腊文
在将来的版本中可能会添加其他语言代码。

spellfix1_translit(X)

此例程将unicode文本音译为纯ascii,返回输入文本X的纯ascii表示形式。此函数在内部用于将词汇转换为影子表的K1列。

8. editdist3函数

editdist3算法是一种计算两个输入字符串之间的最小编辑距离(即Levenshtein距离)的函数。editdist3算法是对spellfix1的默认编辑距离功能的可配置替代。editdist3的功能包括:

9. editdist3 COST表

要编程editdist3的成本,请创建一个如下表:

创建表editcost(
  iLang INT-语言ID
  c从TEXT,-从此转换文本
  cTo TEXT,-将文本转换为此
  iCost INT-进行转换的成本
);

费用表可以命名为任意名称-不必称为“ editcost”。该表可以包含其他列。唯一的要求是该表必须包含上面显示的四列,并准确显示名称。

iLang列是一个非负整数,标识一组适合特定语言的成本。editdist3函数将仅使用单个iLang值进行任何给定的编辑距离计算。默认值为0。建议只需要使用一种语言的应用程序对所有条目始终使用iLang == 0。

iCost列是将cFrom转换为cTo的数字成本。此值应为非负整数,并且应小于100。默认的单字符插入和删除成本为100,默认的单字符到单字符替换成本为150。成本为10000或更高被认为是“无限的”,并导致该规则被忽略。

cFrom和cTo列显示编辑转换字符串。任一列或两列都可能包含多个字符。或任一列(但不能同时包含两列)可能包含一个空字符串。当cFrom为空时,这就是插入cTo的成本。当cTo为空时,这就是删除cFrom的代价。

在spellfix1算法中,cFrom是用户输入的文本,而cTo是数据库中存在的正确拼写的文本。editdist3算法的目标是确定用户输入的文本与字典文本的接近程度。

费用表中有三个特殊情况条目:

c发件人意义
'''?'默认插入费用
'?'''默认删除费用
'?''?'默认替代成本

如果省略了上面显示的任何特殊情况条目,则将值100用于插入和删除,将值150用于替换。要禁用默认的插入,删除和/或替换,请将它们各自的成本设置为10000或更高。

成本表中的其他条目将特定字符转换为特定字符。特定转换的成本应小于默认成本,否则默认成本将优先,并且永远不会使用特定转换。

例如,成本表条目:

插入到editcost(iLang,cFrom,cTo,iCost)中
VALUES(0,'a','ä',5);

上面的规则说,用户输入中的字母“ a”可以与字典中的字母“ä”匹配,罚则为5。

插入到editcost(iLang,cFrom,cTo,iCost)中
VALUES(0,'ss','ß',8);

cFrom和cTo中的字符数不必相同。上面的规则说,用户输入上的“ ss”将与“ß”匹配,罚则为8。

10.试用editcost3()函数

如果在创建spellfix1虚拟表时将“ edit_cost_table = TABLE”选项指定为自变量,则spellfix1虚拟表将使用editdist3。但是,也可以使用内置的“ editdist3()” SQL函数直接测试editdist3。editdist3()SQL函数具有3种形式:

  1. editdist3('TABLENAME');
  2. editdist3('string1','string2');
  3. editdist3('string1','string2',langid);

第一种形式从称为“ TABLENAME”的表加载编辑距离系数。任何先验系数都将被丢弃。因此,当尝试权重和权重表发生变化时,只需重新运行editdist3()的单参数形式即可重新加载修改后的系数。请注意,editdist3()SQL函数使用的编辑距离权重独立于spellfix1虚拟表使用的权重。

第二和第三种形式返回计算的字符串“ string1”和“ string2”之间的编辑距离,在第二种形式中,使用的语言ID为0,在第三种形式中指定了语言ID。