自己动手实现全文搜索引擎之中文切词

56 阅读2分钟

简介

上章简单聊了下爬虫,因为我用的是java,使用jsoup就可以简单实现,最多加个多线程抓取就行,感觉没啥好说的,具体的爬虫实现大家看看别的文章就好。
中文分词就是将一篇文档分成若干字、词,便于之后创建索引文件。分词方法主要有机械匹配算法、统计方法以及基于理解的分词算法。
其中机械匹配算法主要有正向最大匹配和逆向最大匹配,这两个的区别就是匹配的方向不同,正向是从左往右,逆向则是从右往左。除了方向不同,这两种的基本思路都一样,都是先找到一个可以匹配的最大字符串,比如给定最大词语的长度为3,则正向或逆向地找到3个长度的词是否存在于词库,存在就说明匹配成功,反之,则将长度减一继续匹配,直到长度为1时,直接匹配成功,即所有单字都可以匹配成功。 下面举个例子,假如词库中存在如下词语:火柴、小女孩、可怜、真可。
例句:卖火柴的小女孩真可怜。
正向匹配:卖/火柴/的/小女孩/真可/怜。
逆向匹配:可怜/真/小女孩/的/火柴/卖。

逆向最大匹配算法

具体算法

1、从起始位置逆向或正向找到最大长度的字符串,是否匹配,是则将起始位置更改为原起始位置减去或加上(逆向为减,正向为加)最大字符串长度,继续进行步骤1操作;否则,进行步骤2操作。
2、将字符串长度减1,字符串长度是否为1,是则跳到步骤3。是否匹配,是则将起始位置更改为原起始位置减去或加上现字符串的长度,进行步骤1操作;否则,继续进行步骤2操作。
3、单字匹配成功,起始位置更改为原起始位置减或加1。

具体实现

/**
 * 逆向最大匹配
 * @param sentence 句子
 * @param maxL 词语最长
 * @return Stack<HashMap<String,Integer>> result
 */
private Stack<HashMap<String,Integer>> reverseMaxMatch(String sentence, int maxL) {
    Stack<HashMap<String,Integer>> result = new Stack<>();
    for(int j = sentence.length(); j > 0;) {
        HashMap<String,Integer> word = new HashMap<>();
        if(j < maxL) { //小于MAX两种情况:1.本身小于 2.减到最后小于
            maxL = j; //更改最长词语长度为j
        }
        String subWord = sentence.substring(j - maxL, j);
        if(isWordMatch(subWord)) { //subWord是否匹配? 单字都匹配
            word.put(subWord,j);
            result.push(word);
            j -= maxL;
        }else {
            String tempWord = "";
            int k;
            for(k = maxL - 1; k > 0; k--) {
                tempWord = subWord.substring(maxL - k, maxL);
                if(isWordMatch(tempWord)) {
                    break; //tempWOrd匹配就跳出循环,全部单字均匹配
                }
            }
            if(k == 0) k = 1;
            word.put(tempWord,j);
            result.push(word);
            j = j - k;
        }
    }
    return result;
}

其中boolean isWordMatch(String word)方法是用于匹配word是否位于词库的方法,返回的数字指这个词在句子里的最后的位置,减去词长可以得到词的初始位置。