一個簡單的關鍵詞檢測(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…

相關文章
相關標籤/搜索