扩展MySQL 5.7/.../ 编写全文解析器插件

4.4.4编写全文解析器插件

MySQL支持服务器端全文解析器插件MyISAM而且InnoDB.有关全文解析器插件的介绍信息,请参见全文解析器插件

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

指令中使用的源代码插件/全文MySQL源代码发行版的目录,因此将位置更改到该目录。下面介绍如何创建插件库:

  1. 要编写全文解析器插件,请在插件源文件中包含以下头文件。其他MySQL或通用头文件也可能需要,这取决于插件的功能和需求。

    # include < mysql / plugin.h >

    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, /*状态变量*/ simple_system_variables,/*变量*/ NULL, 0} mysql_declare_plugin_end;

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

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

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

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

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

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

    接口版本号使用符号指定,该符号的形式为:MYSQL_xxx_INTERFACE_VERSION.对于全文解析器插件,符号为MYSQL_FTPARSER_INTERFACE_VERSION.在源代码中,您将找到定义的全文解析器插件的实际接口版本号包括/ mysql / plugin_ftparser.h.随着全文解析器插件的引入支持InnoDB,在MySQL 5.7中,接口版本号从0 x01000 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, /*解析器init函数*/ simple_parser_deinit /*解析器deinit函数*/};

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

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

    • 对于搜索,服务器调用解析器来解析搜索字符串。对于语句处理的行,也可以调用解析器。在自然语言模式下,服务器不需要调用解析器。对于布尔模式短语搜索或带有查询扩展的自然语言搜索,解析器用于解析列值以获得不在索引中的信息。此外,如果对一个列执行布尔模式搜索,则该列不包含全文Index时,将调用内置解析器。(插件与特定的索引相关联。如果没有索引,则不使用插件。)

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

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

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

    在插件描述符中命名的每个接口函数成功时返回0,失败时返回非0,并且每个接口函数都接收一个指向a的参数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;构造charset_info_st *cs;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:以stopword模式解析。这用于短语匹配的布尔搜索。解析器应该将所有单词传递给服务器,甚至包括停止词或超出任何正常长度限制的单词。

      • MYSQL_FTPARSER_FULL_BOOLEAN_INFO:布尔模式解析。这用于解析布尔查询字符串。语法分析器不仅应该识别单词,还应该识别布尔模式操作符,并将它们作为标记使用mysql_add_word回调。为了告诉服务器传递的是哪种令牌,插件需要填写一个MYSQL_FTPARSER_BOOLEAN_INFO结构并传递一个指针给它。

    请注意

    MyISAM、停词表和ft_min_word_len而且ft_max_word_len在标记器中进行检查。为InnoDB,停止词列表和等效字长变量设置(innodb_ft_min_token_size而且innodb_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 enum_ft_token_type类型;int yesno;int weight_adjust;char wasign;char trunc;int位置;/*这些是解析器状态,必须删除。*/ char prev;char *”;} MYSQL_FTPARSER_BOOLEAN_INFO;

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

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

      表4.3全文解析器Token类型

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

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

    • weight_adjust:一个权重因素,决定单词的匹配有多重要。在相关性计算中,它可以用来增加或减少单词的重要性。值为0表示不进行权重调整。大于0或小于0的值分别表示更高或更低的权重。例子在布尔全文搜索,使用<而且>运算符说明加权是如何工作的。

    • wasign:权重因子的符号。一个负值就像布尔搜索操作符,它导致单词对相关性的贡献为负。

    • trunc:是否按照布尔模式进行匹配给出了截断算子。

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

    插件不应该使用上一页而且委员会成员MYSQL_FTPARSER_BOOLEAN_INFO结构。

    请注意

    插件解析器框架不支持:

    • @distance布尔操作符。

    • 前导加号(+)或负号(-布尔运算符,后面跟着一个空格,然后是一个单词(' +苹果'“苹果”).前面的加号或减号必须直接与单词相邻,例如:' +苹果'“-苹果”

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

  4. 设置插件接口函数。

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

    静态int simple_parser_plugin_init(void *arg __attribute__((未使用))){返回(0);} static int simple_parser_plugin_deinit(void *arg __attribute__((未使用))){return(0);}

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

    的类型特定的插件描述符simple_parser命名服务器在使用插件时调用的初始化、反初始化和解析函数。为simple_parser,初始化和反初始化函数什么都不做:

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

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

    主要解析功能,simple_parser_parse (),可以替代内置的全文解析器,因此它需要将文本分解成单词,并将每个单词传递给服务器。解析函数的第一个参数是指向包含解析上下文的结构的指针。这个结构有一个医生成员,该成员指向要解析的文本长度成员,该成员指示文本的长度。插件所做的简单解析将非空的空白字符视为单词,因此它像这样识别单词:

    static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param) {char *end, *start, *docend= param->doc + param->length;For (end= start= param->doc;;结束++){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;}} return(0);}

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

    static 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};mysql_add_word(Param, word, len, &bool_info);}

    对于布尔模式解析,add_word ()元素的成员bool_info的讨论中所描述的st_mysql_ftparser_boolean_info结构。

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

    Long number_of_calls= 0;Struct st_mysql_show_var simple_status[]= {{"simple_parser_static", (char *)"只是一个静态文本",SHOW_CHAR}, {"simple_parser_called", (char *)&number_of_calls, SHOW_LONG}, {0,0,0}};

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

    mysql> SHOW STATUS LIKE simple_parser%;+----------------------+--------------------+ | Variable_name |值  | +----------------------+--------------------+ | simple_parser_static |只是一个静态文本| | simple_parser_called | 0  | +----------------------+--------------------+
  6. 要编译和安装插件库文件,请使用第4.4.3节,“编译和安装插件库”.要使库文件可用,请将其安装到插件目录(由plugin_dir系统变量)。为simple_parser当你从源代码构建MySQL时,它会被编译和安装。它也包含在二进制发行版中。构建过程将生成名称为的共享对象库mypluglib.so(所以后缀可能因平台而异)。

  7. 要使用该插件,请将其注册到服务器。例如,要在运行时注册插件,使用此语句,调整所以为你的平台添加必要的后缀:

    SONAME ' myplulib .so';

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

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

  9. 测试插件以验证它是否正常工作。

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

    mysql> CREATE TABLE t (c VARCHAR(255), -> FULLTEXT (c) WITH PARSER simple_parser ->) ENGINE=MyISAM;查询OK, 0行受影响(0.01秒)

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

    mysql> INSERT INTO t VALUES -> ('latin1_general_cs是一个区分大小写的排序规则'),-> ('I\'d like a case of oranges'), ->('这是敏感信息'),->('另一行'),->('另一行');查询OK, 5行影响(0.02秒)记录:5重复:0警告:0 mysql> SELECT c FROM t;+-------------------------------------------------+ | c  | +-------------------------------------------------+ | latin1_general_cs是区分大小写排序| |我要一箱橘子| |这是敏感信息| |另一行| |另一行  | +-------------------------------------------------+ 5行设置(0.00秒)mysql >选择匹配(c)反对(“案件”)从t;+--------------------------+ | 匹配(c)反对(的情况下 ') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0  | +--------------------------+ 5行设置(0.00秒)mysql >选择匹配(c)反对(“敏感”)从t;+-------------------------------+ | 匹配(c)反对(“敏感 ') | +-------------------------------+ | 0 | | 0 | | 1.3253291845322 | | 0 | | 0  | +-------------------------------+ 5行设置(0.01秒)mysql >选择匹配(c)反对(“区分大小写”)从t;+------------------------------------+ | 匹配(c)反对(区分大小写的 ') | +------------------------------------+ | 1.3109166622162 | | 0 | | 0 | | 0 | | 0  | +------------------------------------+ 5行集(0.01秒)mysql >选择匹配(c)反对(我\ ' d ')从t;+--------------------------+ | 匹配(c)反对(我\ ' d ') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0  | +--------------------------+ 5行集(0.01秒)

    既不情况下也不不敏感匹配不区分大小写就像内置解析器一样。