一个简单的关键词检测(DFA)

前言

关键词检测是如今几乎全部网站系统都必需要有的东西。往复杂了作会牵扯到NLP之类的“高级技术”,这个就不在本篇里瞎扯了。这里教你们一个简单的算法:DFA。php

DFA是啥

DFA:Deterministic Finite Automaton,也就是肯定有穷自动机。其特征为:有一个有限状态集合和一些从一个状态通向另外一个状态的边,每条边上标记有一个符号,其中一个状态是初态,某些状态是终态。git

这个描述有点难懂,我用一段白话来讲明一下:你有一个集合,集合内的每个元素都标明了本身的状态,经过你已知的某些事件,你能够从当前元素的状态获得下一个状态,从而知道下一个元素是啥,即event + state = next state。并且毕竟集合是有限的,必定能从一个节点找到最终的节点。github

上图比较清楚的展现了这种集合间元素的关系,状态S经过事件a能够找到U,能够经过事件b找到V。那么怎么把这个有穷自动机用到关键词检测里呢,下面举个例子。算法

举个例子

如今有几个关键词:妙蛙种子,妙蛙草,妙蛙花,皮卡丘,皮丘。咱们如今对这些关键词进行一些操做,构造出一个有穷自动机出来。bash

若是咱们将这些词整理成这样一个树状结构,咱们就能够根据第一个字,去对他所属的树去进行检索,这将大大提升搜索的效率。学习

以妙蛙花为例:网站

  1. 先经过“妙”字去搜索,看看存不存在以“妙”为根节点的树。若不存在,则这个词不在咱们的关键词中。
  2. 若存在这个树,则咱们去匹配第二个字“蛙”,看看这个字是否是在当前这个树的第二个节点上。若不存在话,则这个词不在咱们的关键词中。而后依次类推下去。
  3. 如何判断这棵树已经到最末尾了,即到了关键字最后一个字。咱们在生成这颗树的时候,给最后的节点加上一个属性(isEnd=true),标明这个关键词已经结束了。

下面给出这个自动机的HashSet实例:ui

妙 = { 
    isEnd = 0 
    蛙 = {
        isEnd = 0
        种 = {
            isEnd = 0 
            子 = {
                isEnd = 1
            } 
        } 
        草 = {
            isEnd = 1
        }
        花 = {
            isEnd = 1
        }
    }
}

皮 = {
    isEnd = 0
    卡 = {
        isEnd = 0
        丘 = {
            isEnd = 1
        }
    }
    丘 = {
        isEnd = 1
    }
}

复制代码

代码实现

class DFA
{
    private $tree = [];

    public function build($strWord)
    {

        $len = mb_strlen($strWord, 'UTF-8');
        $tree = &$this->tree;

        for ($i = 0; $i < $len; $i++) {

            $word = mb_substr($strWord, $i, 1, 'UTF-8');

            if (isset($tree[$word])) {

                if ($i == ($len - 1)) {
                    $tree[$word]['end'] = 1;
                }

            } else {

                if ($i == ($len - 1)) {
                    $tree[$word] = [];
                    $tree[$word]['end'] = 1;
                } else {
                    $tree[$word] = [];
                    $tree[$word]['end'] = 0;
                }

            }

            $tree = &$tree[$word];
        }
    }

    public function search($strWord)
    {
        $len = mb_strlen($strWord, 'UTF-8');

        $arrHashMap = $this->tree;

        for ($i = 0; $i < $len; $i++) {

            $word = mb_substr($strWord, $i, 1, 'UTF-8');

            if (!isset($arrHashMap[$word])) {
                $arrHashMap = $this->tree;
                continue;
            }

            if ($arrHashMap[$word]['end']) {
                return true;
            }

            $arrHashMap = $arrHashMap[$word];
        }
        
        return false;
    }
}

$obj = new DFA();
$obj->build('妙蛙种子');
$obj->build('妙蛙草');
$obj->build('皮卡丘');
$obj->build('皮丘');

var_dump($obj->search('迷唇姐'));
var_dump($obj->search('妙蛙种子'));

复制代码

一些问题

  1. 这个检测关键词也是依赖于词库自己,词库自己须要人维护。
  2. 词库若很大的话,会占用不少内存。
  3. 无心义字符会影响查询,须要提早进行过滤。

综上

以上就是使用DFA进行关键词检测的一个简单应用,在一些简单的应用场景里面仍是挺实用的。固然,真正的关键词检测还须要用到深度学习和天然语言分析等相关技术,这些等之后有机会了再研究吧。this

PS

附上仓库spa

github.com/Devil0023/p…

相关文章
相关标签/搜索