PHP和MySql索引上的最佳文本搜索逻辑

时间:2017-11-11 06:05:36

标签: php mysql json indexing innodb

尝试为我的CMS设计索引和搜索系统。

到目前为止我所做的是:

数据库表(POST表)中的三列(InnoDB - utf8mb4_unicode_ci)。

  1. 原创内容(JSON格式)。

  2. 令牌(从JSON获取所有文本,删除停用词,然后将令牌保存到该列),同时启用该列的索引。

  3. 令牌(直接来自标记字段,stackoverflow,如标记。),也为该字段编制索引。

  4. 我的CMS正在研究这种方法,但由于原始内容产生的令牌而增加了索引和表格大小。

    有改进的方法吗?

    我来自JAVA背景(使用Lucane)。我很难写出所有禁言词的字典。如果有人知道预制的API os脚本用于删除禁用词。

2 个答案:

答案 0 :(得分:1)

对于tag系统,如堆栈溢出或许多其他系统,我会使用3个表。

  • 带有json的主表
  • 标签表
  • 多人关系的交汇点或桥牌表。

使用单独的标记表,您可以使用IN=进行搜索。您可以将该表用作自动完成。你"规范化"你的数据,减少它。等等...它确实为查询添加了一些联接和一些复杂性,但我会说它仍然相当简单。

我还在Jquery中编写了一个Text输入插件来识别文本字段中的标签。它基本上没有记录,但欢迎你玩它。

https://github.com/ArtisticPhoenix/jQuery-Plugins/tree/master/jQuery-Plugins/jqWall

这是一个小项目,我们需要一个" twitter"就像带有主题标签的墙一样,所以它可以设置为识别和自动完成,例如用户输入以#开头的标签。允许用户使用标记自动完成文本,并减少错误或拼写错误的标记的发生。您可以定义要匹配的内容,并为其他功能提供一些回调。它使用起来非常简单。

你可以在这个小提琴中看到基本的设置(它很标准很多很多)

https://www.db-fiddle.com/f/2WSaLjtnuDrZE2CcVhAe9S/1

这为您提供了一些其他功能,例如此查询。

SELECT
    t.*
FROM
    tags AS t
LEFT JOIN
    posts_tags AS pt ON t.id = pt.tag_id
WHERE
    pt.tag_id IS NULL;

将选择帖子中未使用的所有标签。同样,很容易计算出有多少帖子具有给定标签。

SELECT
    count(p.id) AS total
FROM
    posts AS p
JOIN
    posts_tags AS pt ON p.id = pt.post_id
JOIN
    tags AS t ON pt.tag_id = t.id
WHERE
    tag = 'Programming';

如果你不习惯像这样的关系如何工作和使用连接,这可能看起来很复杂。但是,如果您有关键字列表,请考虑计算有多少帖子。您将使用keywords LIKE '%Java%',这可能会损害您的性能(无论何时使用前面的%word通配符)。另外值得注意的是,如果您使用Javascript这样的关键字,则会使用此查询对其进行统计,而JavaJavascript完全不同,因此准确统计有多少帖子可能是一项不可能完成的任务你使用了部分字符串匹配。

如果你使用单个字段,我唯一建议的是使用分隔符,并将其包含在内容的正面和背面,就像这样。

 |tag1|tag2|tag|tag10|

原因是您可以在搜索中包含分隔符,请考虑此部分查询

WHERE tag LIKE "%tag%"

现在,如果你搜索它,你会找到所有标签,但因为我们有分隔符,你可以这样做

WHERE tag LIKE "%|tag|%"

哪会限制比赛。但要使它工作,您需要在列表的开头和结尾处使用分隔符。如果我们无法将tag1|tag10|tag|tag|匹配,请考虑此%|tag|%,这样一切都会崩溃。对于使用较少的系统,这可能会ok,但由于索引的性质以及它们如何处理外卡搜索,单独的表仍然更优越。



console.log("type any of these 'Java', 'JavaScript', 'Programming', 'PHP' and press enter to select from list, or use the mouse.");
console.log("press enter to simulate submission, logs contents.");

$('#test').jqWall({
  id: 'jqWall',
  autoComplete: {
    cache: ['Java', 'JavaScript', 'Programming', 'PHP'],
    match: /([^\s]+)$/, //$ ends with is required
    search : function(term, matches, callback){
        if(matches.lenght == 0){
        //get matches array from server by AJAX using `term`
        }
        callback( matches ); //requred
 
      },
  },
  submit : function(wrapper){
    //press enter to submit
    var contents = wrapper.find('textarea').val();
    //you could post contents back to server to save.
    console.log(contents);
  }
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/ArtisticPhoenix/jQuery-Plugins/master/jQuery-Plugins/jqWall/jqWall.js"></script>
<link href="https://rawgit.com/ArtisticPhoenix/jQuery-Plugins/master/jQuery-Plugins/jqWall/jqWall.css" rel="stylesheet" />
<style type="text/css">
  #jqWall textarea {
    width: 400px;
    height: 200px;
  }
</style>


<div id="test" style=""></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您描述两个“标记”列的方式,每个列都需要FULLTEXT索引。然后使用MATCH(token1) AGAINST('+mysql +index IN BOOLEAN MODE)查找关于“mysql”和“index”(或索引或​​索引或索引等)的帖子。