ik分词器中歧义处理

分词的歧义处理是IK分词的一个重要的核心模块,主要使用组合遍历的方式进行处理。从子分词器中取出不相交的分词集合,例如分词结果为abcd(abcd代表词),abcd是按其在文本中出现的位置排序的,从前到后。假如a与b相交,b与c相交,c与d不相交,则将分词结果切成abc和d两个块分别处理

以“中华人民共和国人民”为例,词典为“中华,华人,人民,共和国,国人”

1. 首先将分词结果分组,

“中华”“华人”“人民”为一组封装到LexemePath对象

“共和国”“国人”“人民”为一组封装到LexemePath对象

2. 针对每个LexemePath对象,获取所有的非歧义组合,再次封装为exemePath对象,然后挑选出最后的组合方式

这里以 “共和国”“国人”“人民”这一组为例说明

(1)该组的lexemepath对象的结构为

ik分词器中歧义处理_第1张图片

(2)该组的可选非歧义组合为

ik分词器中歧义处理_第2张图片

(3)最终选取的最优路径是如下路径

ik分词器中歧义处理_第3张图片

因为最优路径比较时,首先考虑有效文本长度,payloadlength=5 VS payloadlength=2 ,前者完胜


总结:

理解歧义处理,最主要的类结构就是LexemePath,其中包括了pathBegin(路径开始位置),pathEnd(路径结束位置), payLoadLength(路径有效文本长度), set (路径中包含的词元)

其中获取歧义词分组,对歧义词分组获取非歧义分组,最优分组都是以LexemePath对象展开的

    void process(AnalyzeContext context, boolean useSmart) {
        QuickSortSet orgLexemes = context.getOrgLexemes();
        Lexeme orgLexeme = orgLexemes.pollFirst();

        LexemePath crossPath = new LexemePath();

        while (orgLexeme != null) {
            if (!crossPath.addCrossLexeme(orgLexeme)) {
                //找到与crossPath不相交的下一个crossPath
                if (crossPath.size() == 1 || !useSmart) {
                    //crossPath没有歧义 或者 不做歧义处理
                    //直接输出当前crossPath
                    context.addLexemePath(crossPath);
                } else {
                    //对当前的crossPath进行歧义处理
                    QuickSortSet.Cell headCell = crossPath.getHead();
                    LexemePath judgeResult = this.judge(headCell, crossPath.getPathLength());
                    //输出歧义处理结果judgeResult
                    context.addLexemePath(judgeResult);
                }

                //把orgLexeme加入新的crossPath中
                crossPath = new LexemePath();
                crossPath.addCrossLexeme(orgLexeme);
            }
            orgLexeme = orgLexemes.pollFirst();
        }


        System.out.println(crossPath);
        //处理最后的path
        if (crossPath.size() == 1 || !useSmart) {
            //crossPath没有歧义 或者 不做歧义处理
            //直接输出当前crossPath
            context.addLexemePath(crossPath);
        } else {
            //对当前的crossPath进行歧义处理
            QuickSortSet.Cell headCell = crossPath.getHead();
            LexemePath judgeResult = this.judge(headCell, crossPath.getPathLength());
            //输出歧义处理结果judgeResult
            context.addLexemePath(judgeResult);
        }
    }
private LexemePath judge(QuickSortSet.Cell lexemeCell, int fullTextLength) {
        //候选路径集合
        TreeSet pathOptions = new TreeSet();
        //候选结果路径
        LexemePath option = new LexemePath();

        //对crossPath进行一次遍历,同时返回本次遍历中有冲突的Lexeme栈
        Stack lexemeStack = this.forwardPath(lexemeCell, option);

        //当前词元链并非最理想的,加入候选路径集合
        pathOptions.add(option.copy());

        //存在歧义词,处理
        QuickSortSet.Cell c = null;
        while (!lexemeStack.isEmpty()) {
            c = lexemeStack.pop();
            //回滚词元链
            this.backPath(c.getLexeme(), option);
            //从歧义词位置开始,递归,生成可选方案
            this.forwardPath(c, option);
            pathOptions.add(option.copy());
        }

        //返回集合中的最优方案
        return pathOptions.first();

    }

public int compareTo(LexemePath o) {
        //比较有效文本长度
        if (this.payloadLength > o.payloadLength) {
            return -1;
        } else if (this.payloadLength < o.payloadLength) {
            return 1;
        } else {
            //比较词元个数,越少越好
            if (this.size() < o.size()) {
                return -1;
            } else if (this.size() > o.size()) {
                return 1;
            } else {
                //路径跨度越大越好
                if (this.getPathLength() > o.getPathLength()) {
                    return -1;
                } else if (this.getPathLength() < o.getPathLength()) {
                    return 1;
                } else {
                    //根据统计学结论,逆向切分概率高于正向切分,因此位置越靠后的优先
                    if (this.pathEnd > o.pathEnd) {
                        return -1;
                    } else if (pathEnd < o.pathEnd) {
                        return 1;
                    } else {
                        //词长越平均越好
                        if (this.getXWeight() > o.getXWeight()) {
                            return -1;
                        } else if (this.getXWeight() < o.getXWeight()) {
                            return 1;
                        } else {
                            //词元位置权重比较
                            if (this.getPWeight() > o.getPWeight()) {
                                return -1;
                            } else if (this.getPWeight() < o.getPWeight()) {
                                return 1;
                            }

                        }
                    }
                }
            }
        }
        return 0;
    }


你可能感兴趣的:(ik分词器中歧义处理)