将MySQL 8.0/.../ 编写全文解析器插件

4.4.4编写全文解析器插件

MySQL支持服务器端全文解析器插件MyISAMInnoDB.有关全文解析器插件的介绍性信息,请参见全文解释器插件

可以使用全文解析器插件替换或修改内置的全文解析器。本节介绍如何编写一个名为simple_parser.这个插件基于比MySQL内置全文解析器使用的更简单的规则执行解析:Words是空白字符的非空运行。

指令使用源代码插件/全文MySQL源分发版的目录,所以将位置更改到该目录。下面的过程描述了插件库是如何创建的:

  1. 要编写一个全文解析器插件,请在插件源文件中包含以下头文件。根据插件的功能和需求,可能还需要其他MySQL头文件或一般头文件。

    # include < mysql / plugin.h >

    插件定义MYSQL_FTPARSER_PLUGIN服务器插件类型和声明插件所需的数据结构。

  2. 为插件库文件设置库描述符。

    此描述符包含服务器插件的通用插件描述符。对于全文解析器插件,类型必须是MYSQL_FTPARSER_PLUGIN.这是标识插件是合法使用的值与解析器条款在创建全文索引。(没有其他插件类型是合法的这个子句。)

    例如,包含单个全文解析器插件的库描述符名为simple_parser是这样的:

    mysql_declare_plugin(ftexample) {MYSQL_FTPARSER_PLUGIN, /* type */ &simple_parser_descriptor, /* descriptor */ "simple_parser", /* name */ "Oracle Corporation", /* author */ "Simple Full-Text Parser", /* description */ PLUGIN_LICENSE_GPL, /* plugin license */ simple_parser_plugin_init,/* init函数(加载时)*/ simple_parser_plugin_deinit,/* deinit函数(未加载时)*/ 0x0001, /* version */ simple_status, /* status variables */ simple_system_variables, /* system variables */ NULL, 0} mysql_declare_plugin_end;

    的名字成员(simple_parser)表示在语句中引用插件时使用的名称,例如安装插件卸载插件.所显示的名称显示插件INFORMATION_SCHEMA。插件

    有关更多信息,请参阅第4.4.2.1节,“服务器插件库和插件描述符”

  3. 设置特定于类型的插件描述符。

    库描述符中的每个通用插件描述符都指向一个特定于类型的描述符。对于全文解析器插件,特定于类型的描述符是st_mysql_ftparser结构插件文件:

    Struct st_mysql_ftparser {int interface_version;int(*解析)(MYSQL_FTPARSER_PARAM *参数);int (* init) (MYSQL_FTPARSER_PARAM *参数);int (* deinit) (MYSQL_FTPARSER_PARAM *参数);};

    如结构定义所示,描述符有一个接口版本号,并包含指向三个函数的指针。

    使用符号指定接口版本号,该符号是表单的:MYSQL_xxx_INTERFACE_VERSION.对于全文解析器插件,符号为mysql_ftparser_interface_version..在源代码中,您将找到所定义的全文Parser插件的实际接口版本号包括/ mysql / plugin_ftparser.h.当前接口版本号为0 x0101

    在里面deinit如果不需要该功能,成员应指向函数或设置为0。的解析成员必须指向执行解析的函数。

    simple_parser声明,该描述符由&simple_parser_descriptor..描述符指定全文插件接口的版本号(由mysql_ftparser_interface_version.),以及插件的解析、初始化和反初始化函数:

    static struct st_mysql_ftparser simple_parser_descriptor= {MYSQL_FTPARSER_INTERFACE_VERSION, /*接口版本*/ simple_parser_parse, /*解析函数*/ simple_parser_init, /*解析初始函数*/ simple_parser_deinit /*解析deinit函数*/};

    全文解析器插件用于两种不同的上下文中:索引和搜索。在这两种情况下,服务器在处理导致插件被调用的每个SQL语句的开始和结束时调用初始化和反初始化函数。但是,在语句处理过程中,服务器会以特定于上下文的方式调用主解析函数:

    • 对于索引,服务器为要索引的每个列值调用解析器。

    • 对于搜索,服务器调用解析器来解析搜索字符串。还可以对由语句处理的行调用解析器。在自然语言模式下,服务器不需要调用解析器。对于布尔模式短语搜索或带有查询展开的自然语言搜索,解析器用于解析索引中没有的信息的列值。同样,如果对没有的列进行布尔模式搜索全文索引时,将调用内置解析器。(插件与特定的索引相关联。如果没有索引,则不使用插件。)

    一般插件描述符中的插件声明具有在里面deinit指向初始化和反初始化函数的成员,以及它所指向的特定类型的插件描述符。然而,这些函数对有不同的目的,并且被调用的原因也不同:

    • 对于通用插件描述符中的插件声明,在加载和卸载插件时调用初始化和反初始化函数。

    • 对于特定于类型的插件描述符,每个SQL语句调用初始化和除通化函数,用于使用该插件。

    插件描述符中命名的每个接口函数都应该返回零,以便成功或非零进行失败,每个函数都会出现故障,每个函数都会收到指向的参数mysql_ftparser_param.包含解析上下文的结构。该结构的定义如下:

    Typedef struct st_mysql_ftparser_param {int (*mysql_parse)(struct st_mysql_ftparser_param *, char *doc, int doc_len);int (*mysql_add_word)(struct st_mysql_ftparser_param *, char *word, int word_len, MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);void * ftparser_state;void * mysql_ftparam;struct charset_info_st * c;char *医生;int长度;int旗帜;enum enum_ftparser_mode模式;} MYSQL_FTPARSER_PARAM;

    结构构件的使用方法如下:

    • mysql_parse:一个指向调用服务器内置解析器的回调函数的指针。当插件充当内置解析器的前端时,使用这个回调函数。也就是说,当插件解析函数被调用时,它应该处理输入以提取文本并将文本传递给mysql_parse打回来。

      这个回调函数的第一个参数应该是帕纳价值本身:

      param-> mysql_parse(param,...);

      前端插件可以一次提取文本并将其全部传递给内置解析器,也可以一次提取文本并将其一部分传递给内置解析器。但是,在这种情况下,内置解析器将文本片段视为它们之间有隐式的断词。

    • mysql_add_word.:指向回调函数的指针,该函数将一个单词添加到全文索引或搜索词列表中。当解析器插件替换内置解析器时使用此回调。也就是说,当插件解析函数被调用时,它应该将输入解析为单词并调用mysql_add_word.回调每个单词。

      这个回调函数的第一个参数应该是帕纳价值本身:

      param - > mysql_add_word (param,…);
    • ftparser_state:这是一个通用指针。插件可以将其设置为以其自身目的在内部使用的信息指向。

    • mysql_ftparam.:由服务器设置。对象的第一个参数传递给mysql_parsemysql_add_word.打回来。

    • cs:指向文本字符集的信息,如果没有任何信息,则为0。

    • 博文:指向要解析的文本的指针。

    • 长度:要解析的文本的长度,以字节为单位。

    • 旗帜:解析器标志。如果没有特殊标志,这为零。唯一的非零旗是MYSQL_FTFLAGS_NEED_COPY,这意味着mysql_add_word ()必须保存该单词的副本(也就是说,它不能使用指向该单词的指针,因为该单词位于将被覆盖的缓冲区中。)

      这个标志可以由MySQL在调用解析器插件之前设置或重置,也可以由解析器插件本身设置或重置mysql_parse ()功能。

    • 模式:解析模式。这个值将是下列常数之一:

      • MYSQL_FTPARSER_SIMPLE_MODE:以快速和简单的模式解析,该模式用于索引和自然语言查询。解析器应仅传递给服务器,只能索引那些应该索引的单词。如果解析器使用长度限制或停止播放列表以确定要忽略的哪些单词,则它不应该将这些单词传递给服务器。

      • mysql_ftparser_with_stopwords.:以停止字模式解析。这在布尔搜索中用于短语匹配。解析器应该将所有单词传递给服务器,甚至包括停止单词或超出任何正常长度限制的单词。

      • MYSQL_FTPARSER_FULL_BOOLEAN_INFO:布尔模式解析。这用于解析布尔查询字符串。语法分析器不仅应该识别单词,还应该识别布尔模式的操作符,并将它们作为令牌传递给服务器mysql_add_word.打回来。要告诉服务器正在通过什么样的令牌,插件需要填写一个mysql_ftparser_boolean_info.结构并传递指针。

    请注意

    MyISAM、停止词列表和ft_min_word_lenft_max_word_len.在记号赋予器内部进行检查。为InnoDB,停止词列表和等效的单词长度变量设置(innodb_ft_min_token_sizeinnodb_ft_max_token_size.)在记号赋予器之外进行检查。作为一个结果,InnoDB插件解析器不需要检查停止词列表,innodb_ft_min_token_size,或innodb_ft_max_token_size..相反,建议返回所有的单词InnoDB.但是,如果要检查插件解析器中的停止字,请使用MYSQL_FTPARSER_SIMPLE_MODE,用于全文搜索索引和自然语言搜索。为mysql_ftparser_with_stopwords.MYSQL_FTPARSER_FULL_BOOLEAN_INFO模式,建议返回所有单词InnoDB包括停止词,在短语搜索时。

    如果以布尔模式调用解析器,则param - >模式值将被MYSQL_FTPARSER_FULL_BOOLEAN_INFO.的mysql_ftparser_boolean_info.解析器用于将令牌信息传递给服务器的结构如下所示:

    Typedef struct st_mysql_ftparser_boolean_info {enum枚举ft_token_type类型;int yesno;int weight_adjust;char wasign;char trunc;int位置;/*这些是解析器状态,必须被删除。* /字符:;char *”;} MYSQL_FTPARSER_BOOLEAN_INFO;

    解析器应该按如下方式填充结构成员:

    • 类型:令牌类型。下表显示了允许的类型。

      表4.3全文解析标记类型

      令牌值 意义
      FT_TOKEN_EOF 最终的数据
      FT_TOKEN_WORD 常规的单词
      FT_TOKEN_LEFT_PAREN 组或子表达的开始
      FT_TOKEN_RIGHT_PAREN 结尾一组或子表达式的结尾
      FT_TOKEN_STOPWORD 一个stopword

    • yesno:是否该单词必须存在才能发生匹配。0表示该词是可选的,但如果该词存在,则增加匹配相关性。值大于0表示必须存在该单词。值小于0表示该单词不能出现。

    • 权力_Adjust.:一个权重因子,它决定了单词匹配的数量。它可以用来增加或减少单词在关联计算中的重要性。值为0表示没有权重调整。大于或小于零的值分别表示更高或更低的权重。的例子布尔全文搜索,使用<>运算符演示了加权的工作原理。

    • was:加权因子的标志。负值是这样的布尔搜索运算符,它使单词对相关性的贡献为负。

    • Trunc.:匹配是否应该像布尔模式一样进行截断运营商已给出。

    • 位置:以字节为单位的文档中单词的启动位置。使用InnoDB全文搜索。对于在布尔模式下调用的现有插件,必须为位置构件添加支持。

    插件不应该使用上一页成员mysql_ftparser_boolean_info.结构。

    请注意

    插件解析器框架不支持:

    • @distance布尔操作符。

    • 前导加号(+)或减号(-)布尔运算符,后接空格,后接单词('+苹果''- 苹果')。前导加号或减号必须直接与单词相邻,例如:' +苹果'“-苹果”

    有关Boolean全文搜索运算符的信息,请参阅布尔全文搜索

  4. 设置插件接口功能。

    库描述符中的通用插件描述符命名了服务器在加载和卸载插件时应该调用的初始化和反初始化函数。为simple_parser,这些函数什么也不做,只是返回0来表示它们成功了:

    static int simple_parser_plugin_init(void * arg ___attribute __((未使用))){return(0);} static int simple_parser_plugin_deinit(void * arg ___attribute __((未使用))){return(0);}

    因为这些函数实际上不做任何事情,你可以省略它们,并在插件声明中为每个函数指定0。

    特定于类型的插件描述符simple_parser命名服务器在使用该插件时调用的初始化,deInitialization和解析功能。为simple_parser,初始化和Deinitialization函数没有什么:

    静态int simple_parser_init(MYSQL_FTPARSER_PARAM *param __attribute__((未使用))){返回(0);} static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param __attribute__((未使用))){返回(0);}

    这里也是如此,因为这些函数什么也不做,所以您可以省略它们,并在插件描述符中为每个函数指定0。

    主要的解析函数,simple_parser_parse (),作为内置全文解析器的替代,因此它需要将文本拆分为单词,并将每个单词传递给服务器。解析函数的第一个参数是一个指向包含解析上下文的结构的指针。这个结构有一个博文成员,该成员指向要解析的文本长度指示文本是多长时间的成员。Plugin的简单解析考虑了Nonempty运行的空白空格字符是单词,因此它标识如下所示:

    static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param) {char *end, *start, *docend= param->doc + param->length;For (end= start= param->doc;;End ++) {if (End == docend) {if (End > start) add_word(param, start, End - start);打破;} else if (isspace(*end)) {if (end > start) add_word(param, start, end - start);Start = end + 1;}}返回(0);}

    当解析器找到每个单词时,它调用一个函数add_word ()将单词传递给服务器。add_word ()只是一个辅助函数;它不是插件接口的一部分。解析器将解析上下文指针传递到add_word (),以及一个指向单词的指针和一个长度值:

    静态void add_word(mysql_ftparser_param * param,char * word,size_t len){mysql_ftparser_boolean_info bool_info = {ft_token_word,0,0,0,0,0,'',0};param-> mysql_add_word(param,word,len,&bool_info);}

    boolean-mode解析,add_word ()填写成员bool_info如前所述在讨论中描述的结构st_mysql_ftparser_boolean_info.结构。

  5. 设置状态变量。为simple_parser下面的状态变量数组设置一个状态变量的值为静态文本,另一个值存储在一个长整数变量中:

    长number_of_calls = 0;Struct st_mysql_show_var simple_status[]= {{"simple_parser_static", (char *)"just a static text", SHOW_CHAR}, {"simple_parser_called", (char *)&number_of_calls, SHOW_LONG}, {0,0,0}};

    通过使用插件名开头的状态变量名,您可以很容易地显示插件的变量显示状态

    MySQL>显示“simple_parser%”等地位;+ -------------------------------------- + |变量_name |价值|+ -------------------------------------- + |simple_parser_static |只是一个静态文本||simple_parser_called |0 | +----------------------+--------------------+
  6. 要编译并安装插件库文件,请使用说明第4.4.3节,“编译和安装插件库”.要使库文件可用,请在插件目录中安装它(由此指定的目录plugin_dir系统变量)。为simple_parser当你从源代码构建MySQL时,它会被编译和安装。它也包含在二进制发行版中。生成过程将生成一个名为mypluglib.so(。所以后缀可能因平台而异)。

  7. 要使用插件,请在服务器上注册它。例如,要在运行时注册插件,可以使用这个语句,调整。所以必要时为您的平台添加后缀:

    安装插件simple_parser SONAME 'mypluglib.so';

    有关插件加载的其他信息,请参见安装和卸载插件

  8. 要验证插件安装,请检查INFORMATION_SCHEMA。插件表或使用显示插件声明。看到获取服务器插件信息

  9. 测试插件,以验证其工作正常。

    创建一个包含字符串列的表,并将解析器插件与全文列上的索引:

    MySQL>创建表T(C varchar(255), - >用Parser Simple_Parser  - >)引擎= Myisam;查询OK,影响0行(0.01秒)

    向表中插入一些文本并尝试一些搜索。这些应该验证解析器插件将所有非空白字符视为单词字符:

    mysql> INSERT INTO t VALUES -> ('utf8mb4_0900_as_cs is a case-sensitive collation'), -> ('I\'d like a case of oranges'), -> ('this is sensitive information'), -> ('another row'), -> ('yet another row');查询OK, 5行影响(0.02秒)记录:5重复:0警告:0 mysql> SELECT c FROM t;+--------------------------------------------------+ | c  | +--------------------------------------------------+ | utf8mb4_0900_as_cs是区分大小写排序| |我要一箱橘子| |这是敏感信息| |另一行| |另一行  | +--------------------------------------------------+ 5行集(0.00秒)mysql >SELECT MATCH(c) AGAINST('case') FROM t; +--------------------------+ | MATCH(c) AGAINST('case') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.00 sec) mysql> SELECT MATCH(c) AGAINST('sensitive') FROM t; +-------------------------------+ | MATCH(c) AGAINST('sensitive') | +-------------------------------+ | 0 | | 0 | | 1.3253291845322 | | 0 | | 0 | +-------------------------------+ 5 rows in set (0.01 sec) mysql> SELECT MATCH(c) AGAINST('case-sensitive') FROM t; +------------------------------------+ | MATCH(c) AGAINST('case-sensitive') | +------------------------------------+ | 1.3109166622162 | | 0 | | 0 | | 0 | | 0 | +------------------------------------+ 5 rows in set (0.01 sec) mysql> SELECT MATCH(c) AGAINST('I\'d') FROM t; +--------------------------+ | MATCH(c) AGAINST('I\'d') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.01 sec)

    两者都不案件也不不敏感匹配不区分大小写就像内置解析器那样。