NLPChina_ansj_seg JAVA 实现热词及分词统计

那年仲夏 提交于 2020-10-08 10:24:40

前言:

笔者最近遇到一个需求:将文章输入后输出文章中的高频词,这是个简短的需求,但细分下便会出现许多细节重点。笔者细化需求后确定了这几个步骤:1. 文章分词(包括中英文混词)——> 2. 分词统计——>3. 推荐热词。

根据上述的简单需求,我就想用原生JAVA通过某些数据结构实现,由于知识面有限且笔者目前是名在校的学生,实现了英文下的分词、中文下的分词。但是遇到中英文混排的怎么也合并不了。经过两天的各种思考各种分析结果以失败告终。在查阅资料的时候发现了阿帕奇的OpenNLP 工具,然后仔细的看了看源码。。看的也是云里雾里的,但基本思想也了解了。虽然阿帕奇的OpenNLP很牛逼,但是我还是选择了一个国人自产基于n-Gram+CRF+HMM的分词JAVA实现。具体开发文档和源码可以访问GITHUB

废话不多说上源码。

工具类:

package com.sim;

import org.ansj.splitWord.analysis.ToAnalysis;

import java.io.*;
import java.util.*;

public class NLPTools {

    public static Map<String,String> wordFrequency(String article) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        Map<String,String > info = new HashMap<String, String>();
        String result = ToAnalysis.parse(article).toStringWithOutNature();
        System.out.println(result);
        String[] words = result.split(",");


        for(String word: words){
            String str = word.trim();
            // 过滤空白字符
            if (str.equals(""))
                continue;
                // 过滤一些高频率的符号
            else if(str.matches("[)|(|.|,|。|+|-|“|”|:|?|\\s]"))
                continue;
                // 此处过滤长度为1的str
            else if (str.length() < 2)
                continue;

            if (!map.containsKey(word)){
                map.put(word, 1);
            } else {
                int n = map.get(word);
                map.put(word, ++n);
            }
        }

        StringBuffer cp = new StringBuffer();// 词频
        StringBuffer rc = new StringBuffer();// 热词

        Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> entry = iterator.next();
            cp.append(entry.getKey() + ": " + entry.getValue()+"\t");
            //System.out.print(entry.getKey() + ": " + entry.getValue()+"\t");
        }
        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>();
        Map.Entry<String, Integer> entry;
        while ((entry = getMax(map)) != null){
            list.add(entry);
        }
//        System.out.print("\n前五热词为:");
        rc.append("前五热词为:");
        for (int i = 0; i < 5; i++) {
            rc.append(""+list.get(i)+"\t");
//            System.out.print(list.get(i)+"\t");
        }
        info.put("cp",cp.toString());
        info.put("rc",rc.toString());
        return info;
//        System.out.println(Arrays.toString(list.toArray()));

    }


    /**
     * 找出map中value最大的entry, 返回此entry, 并在map删除此entry
     * @param map
     * @return
     */
    public static Map.Entry<String, Integer> getMax(Map<String, Integer> map){
        if (map.size() == 0){
            return null;
        }
        Map.Entry<String, Integer> maxEntry = null;
        boolean flag = false;
        Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> entry = iterator.next();
            if (!flag){
                maxEntry = entry;
                flag = true;
            }
            if (entry.getValue() > maxEntry.getValue()){
                maxEntry = entry;
            }
        }
        map.remove(maxEntry.getKey());
        return maxEntry;
    }

    /**
     * 从文件中读取待分割的文章素材.
     * @return
     * @throws IOException
     */
    public static String getString() throws IOException {
        FileInputStream inputStream = new FileInputStream(new File("e://a.txt"));
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder strBuilder = new StringBuilder();

        String line;
        while((line = reader.readLine()) != null){
            strBuilder.append(line);
        }
        reader.close();
        inputStream.close();
        return strBuilder.toString();
    }
}

测试类:

package com.sim;

import org.ansj.splitWord.analysis.ToAnalysis;

import java.util.ArrayList;
import java.util.List;

public class JTest {
    public static void main(String[] args) throws Exception{
        String str = "这几天心里颇不宁静。今晚在院子里坐着乘凉,忽然想起日日走过的荷塘,在这满月的光里,总该另有一番样子吧。月亮渐渐地升高了,墙外马路上孩子们的欢笑,已经听不见了;妻在屋里拍着闰儿,迷迷糊糊地哼着眠歌。我悄悄地披了大衫,带上门出去。\n" +
                "  沿着荷塘,是一条曲折的小煤屑路。这是一条幽僻的路;白天也少人走,夜晚更加寂寞。荷塘四面,长着许多树,蓊蓊郁郁的。路的一旁,是些杨柳,和一些不知道名字的树。没有月光的晚上,这路上阴森森的,有些怕人。今晚却很好,虽然月光也还是淡淡的。\n" +
                "  路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常的自己,到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。像今晚上,一个人在这苍茫的月下,什么都可以想,什么都可以不想,便觉是个自由的人。白天里一定要做的事,一定要说的话,现在都可不理。这是独处的妙处,我且受用这无边的荷香月色好了。\n" +
                "  曲曲折折的荷塘上面,弥望的是田田的叶子。叶子出水很高,像亭亭的舞女的裙。层层的叶子中间,零星地点缀着些白花,有袅娜地开着的,有羞涩地打着朵儿的;正如一粒粒的明珠,又如碧天里的星星,又如刚出浴的美人。微风过处,送来缕缕清香,仿佛远处高楼上渺茫的歌声似的。这时候叶子与花也有一丝的颤动,像闪电般,霎时传过荷塘的那边去了。叶子本是肩并肩密密地挨着,这便宛然有了一道凝碧的波痕。叶子底下是脉脉的流水,遮住了,不能见一些颜色;而叶子却更见风致了。";
        System.out.println(NLPTools.wordFrequency(str));
    }
}

 使用朱自清散文荷塘月色部分节选片段进行分词。

结果:

返回的是map ,前面是排序后的热词后面是所有词的统计。好了,到这里测试还没结束,因为中文/英文单语言实现还是非常简单的,如果中英混杂呢?

 

所以正常通过。还是很nice的。 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!