<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 代碼實(shí)現(xiàn)——使用 IK 分詞器進(jìn)行詞頻統(tǒng)計(jì)

          共 3705字,需瀏覽 8分鐘

           ·

          2021-12-14 18:26

          本文主要介紹如何通過 IK 分詞器進(jìn)行詞頻統(tǒng)計(jì)。

          使用分詞器對文章的詞頻進(jìn)行統(tǒng)計(jì),主要目的是實(shí)現(xiàn)如下圖所示的詞云功能,可以找到文章內(nèi)的重點(diǎn)詞匯。

          后續(xù)也可以對詞進(jìn)行詞性標(biāo)注,實(shí)體識別以及對實(shí)體的情感分析等功能。

          來自銘毅老哥對電影《長津湖》的影評分析

          詞頻統(tǒng)計(jì)服務(wù)具體模塊如下:

          • 數(shù)據(jù)輸入:文本信息
          • 數(shù)據(jù)輸出:詞 - 詞頻(TF-IDF等) - 詞性等內(nèi)容
          • 使用的組件:分詞器、語料庫、詞云展示組件等
          • 功能點(diǎn):白名單,黑名單,同義詞等

          現(xiàn)存的中文分詞器有 IK、HanLP、jieba 和 NLPIR 等幾種,不同分詞器各有特點(diǎn),本文使用 IK 實(shí)現(xiàn),因?yàn)?ES 一般使用 medcl 等大佬封裝的 IK 分詞器插件作為中文分詞器。

          由于 ES 的 IK 分詞器插件深度結(jié)合了 ES,僅對文本分詞使用不到 ES 的內(nèi)容,所以文本采用申艷超大佬版本的 IK。

          IK 地址:https://github.com/blueshen/ik-analyzer

          1. IK 分詞統(tǒng)計(jì)代碼

          IK 的代碼相對比較簡單,東西不多,將 String 拆分為詞并統(tǒng)計(jì)代碼如下:

          1. 單純統(tǒng)計(jì)詞頻:
          /**
          ?*?全文本詞頻統(tǒng)計(jì)
          ?*
          ?*?@param?content??文本內(nèi)容
          ?*?@param?useSmart?是否使用?smart
          ?*?@return?詞,詞頻
          ?*?@throws?IOException
          ?*/
          private?static?Map?countTermFrequency(String?content,?Boolean?useSmart)?throws?IOException?{
          ????//?輸出結(jié)果?Map
          ????Map?frequencies?=?new?HashMap<>();
          ????if?(StringUtils.isBlank(content))?{
          ????????return?frequencies;
          ????}
          ????DefaultConfig?conf?=?new?DefaultConfig();
          ????conf.setUseSmart(useSmart);
          ????//?使用?IKSegmenter?初始化文本信息并加載詞典
          ????IKSegmenter?ikSegmenter?=?new?IKSegmenter(new?StringReader(content),?conf);
          ????Lexeme?lexeme;
          ????while?((lexeme?=?ikSegmenter.next())?!=?null)?{
          ????????if?(lexeme.getLexemeText().length()?>?1)?{//?過濾單字,也可以過濾其他內(nèi)容,如數(shù)字和單純符號等內(nèi)容
          ????????????final?String?term?=?lexeme.getLexemeText();
          ????????????//?Map?累加操作
          ????????????frequencies.compute(term,?(k,?v)?->?{
          ????????????????if?(v?==?null)?{
          ????????????????????v?=?1;
          ????????????????}?else?{
          ????????????????????v?+=?1;
          ????????????????}
          ????????????????return?v;
          ????????????});
          ????????}
          ????}
          ????return?frequencies;
          }
          1. 統(tǒng)計(jì)詞頻和文檔頻率:
          /**
          ?*?文本列表詞頻和詞文檔頻率統(tǒng)計(jì)
          ?*
          ?*?@param?docs?????文檔列表
          ?*?@param?useSmart?是否使用只能分詞
          ?*?@return?詞頻列表?詞-[詞頻,文檔頻率]
          ?*?@throws?IOException
          ?*/
          private?static?Map?countTFDF(List?docs,?boolean?useSmart)?throws?IOException?{
          ????//?輸出結(jié)果?Map
          ????Map?frequencies?=?new?HashMap<>();
          ????for?(String?doc?:?docs)?{
          ????????if?(StringUtils.isBlank(doc))?{
          ????????????continue;
          ????????}
          ????????DefaultConfig?conf?=?new?DefaultConfig();
          ????????conf.setUseSmart(useSmart);
          ????????//?使用?IKSegmenter?初始化文本信息并加載詞典
          ????????IKSegmenter?ikSegmenter?=?new?IKSegmenter(new?StringReader(doc),?conf);
          ????????Lexeme?lexeme;
          ????????//?用于文檔頻率統(tǒng)計(jì)的?Set
          ????????Set?terms?=?new?HashSet<>();
          ????????while?((lexeme?=?ikSegmenter.next())?!=?null)?{
          ????????????if?(lexeme.getLexemeText().length()?>?1)?{
          ????????????????final?String?text?=?lexeme.getLexemeText();
          ????????????????//?進(jìn)行詞頻統(tǒng)計(jì)
          ????????????????frequencies.compute(text,?(k,?v)?->?{
          ????????????????????if?(v?==?null)?{
          ????????????????????????v?=?new?Integer[]{1,?0};
          ????????????????????}?else?{
          ????????????????????????v[0]?+=?1;
          ????????????????????}
          ????????????????????return?v;
          ????????????????});
          ????????????????terms.add(text);
          ????????????}
          ????????}?
          ????????//?進(jìn)行文檔頻率統(tǒng)計(jì):無需初始化 Map,統(tǒng)計(jì)詞頻后 Map 里面必有該詞記錄
          ????????for?(String?term?:?terms)?{
          ????????????frequencies.get(term)[1]?+=?1;
          ????????}
          ????}
          ????return?frequencies;
          }

          2. 獲取詞云 TopN 個詞

          獲取 TopN 個詞用于詞云展示有多種排序方式,可以直接根據(jù)詞頻、文檔頻率或者 TF-IDF 等算法進(jìn)行排序,本文僅根據(jù)詞頻求取 TopN。M 個數(shù)字獲取 TopN 有以下算法:

          • M 小 N 小:快速選擇算法
          • M 大 N 小:小頂堆
          • M 大 N 大:歸并排序

          本文采用小頂堆方式實(shí)現(xiàn),對應(yīng)JAVA中的優(yōu)先隊(duì)列數(shù)據(jù)結(jié)構(gòu) PriorityQueue:

          /**
          ?*?按出現(xiàn)次數(shù),從高到低排序取?TopN
          ?*
          ?*?@param?data?詞和排序數(shù)字對應(yīng)的?Map
          ?*?@param?TopN?詞云展示的?TopN
          ?*?@return?前?N?個詞和排序值
          ?*/
          private?static?List>?order(Map?data,?int?topN)?{
          ????PriorityQueue>?priorityQueue?=?new?PriorityQueue<>(data.size(),?new?Comparator>()?{
          ????????@Override
          ????????public?int?compare(Map.Entry?o1,?Map.Entry?o2)?{
          ????????????return?o2.getValue().compareTo(o1.getValue());
          ????????}
          ????});
          ????for?(Map.Entry?entry?:?data.entrySet())?{
          ????????priorityQueue.add(entry);
          ????}
          ????//TODO?當(dāng)前100詞頻一致時(概率極低)的處理辦法,if(?list(0).value?==?list(99).value?){xxx}
          ????List>?list?=?new?ArrayList<>();
          ????//統(tǒng)計(jì)結(jié)果隊(duì)列size和topN值取較小值列表
          ????int?size?=?priorityQueue.size()?<=?topN???priorityQueue.size()?:?topN;
          ????for?(int?i?=?0;?i?????????list.add(priorityQueue.remove());
          ????}
          ????return?list;
          }

          3. IK 代碼淺析

          核心主類為IKSegmenter,需要關(guān)注的點(diǎn)有dic包也就是詞典相關(guān)內(nèi)容以及字符處理工具類CharacterUtilidentifyCharType()方法,目錄結(jié)構(gòu)如下:

          IK 代碼結(jié)構(gòu)

          IKSegmenter類結(jié)構(gòu)如下圖,其中 init() 為私有方法,初始化加載詞典采用非懶加載模式,在第一次初始化IKSegmenter實(shí)例時會調(diào)用并加載詞典,代碼位于結(jié)構(gòu)圖下方。

          IKSegmenter 類結(jié)構(gòu)
          //?IKSegmenter?類構(gòu)造方法
          public?IKSegmenter(Reader?input,?Configuration?cfg)?{
          ????this.input?=?input;
          ????this.cfg?=?cfg;
          ????this.init();
          }
          //?IKSegmenter?類初始化
          private?void?init()?{
          ????//初始化詞典單例
          ????Dictionary.initial(this.cfg);
          ????//初始化分詞上下文
          ????this.context?=?new?AnalyzeContext(this.cfg);
          ????//加載子分詞器
          ????this.segmenters?=?this.loadSegmenters();
          ????//加載歧義裁決器
          ????this.arbitrator?=?new?IKArbitrator();
          }

          //?Dictionary?類初始化詞典
          public?static?Dictionary?initial(Configuration?cfg)?{
          ????if?(singleton?==?null)?{
          ????????synchronized?(Dictionary.class)?{
          ????????????if?(singleton?==?null)?{
          ????????????????singleton?=?new?Dictionary(cfg);
          ????????????????return?singleton;
          ????????????}
          ????????}
          ????}
          ????return?singleton;
          }

          詞典私有構(gòu)造方法Dictionary()內(nèi)會加載 IK 自帶的詞典以及擴(kuò)展詞典,我們也可以把自己線上不變的詞典放到這里這樣IKAnalyzer.cfg.xml中就只需要配置經(jīng)常變更詞典即可。

          private?Dictionary(Configuration?cfg)?{
          ????this.cfg?=?cfg;
          ????this.loadMainDict();//?主詞典以及擴(kuò)展詞典
          ????this.loadmiaozhenDict();//?自定義詞典加載,仿照其他方法即可
          ??? this.loadStopWordDict();//?擴(kuò)展停詞詞典
          ????this.loadQuantifierDict();//?量詞詞典
          }

          IKSegmenter類調(diào)用next()方法獲取下一個詞元時,會調(diào)用CharacterUtil類中的identifyCharType()方法識別字符種類,這里我們也可以自定義一些字符種類針對處理新興的網(wǎng)絡(luò)語言,如@、##等內(nèi)容:

          static?int?identifyCharType(char?input)?{
          ????if?(input?>=?'0'?&&?input?<=?'9')?{
          ????????return?CHAR_ARABIC;
          ????}?else?if?((input?>=?'a'?&&?input?<=?'z')?||?(input?>=?'A'?&&?input?<=?'Z'))?{
          ????????return?CHAR_ENGLISH;
          ????}?else?{
          ????????Character.UnicodeBlock?ub?=?Character.UnicodeBlock.of(input);
          ????????//caster?增加#為中文字符
          ????????if?(ub?==?Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
          ????????????????||?ub?==?Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
          ????????????????||?ub?==?Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A?||input=='#')?{
          ????????????//目前已知的中文字符UTF-8集合
          ????????????return?CHAR_CHINESE;

          ????????}?else?if?(ub?==?Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS?//全角數(shù)字字符和日韓字符
          ????????????????//韓文字符集
          ????????????????||?ub?==?Character.UnicodeBlock.HANGUL_SYLLABLES
          ????????????????||?ub?==?Character.UnicodeBlock.HANGUL_JAMO
          ????????????????||?ub?==?Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO
          ????????????????//日文字符集
          ????????????????||?ub?==?Character.UnicodeBlock.HIRAGANA?//平假名
          ????????????????||?ub?==?Character.UnicodeBlock.KATAKANA?//片假名
          ????????????????||?ub?==?Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS)?{
          ????????????return?CHAR_OTHER_CJK;

          ????????}
          ????}
          ????//其他的不做處理的字符
          ????return?CHAR_USELESS;
          }

          由于 IK 內(nèi)容不多,建議大家可以從頭捋一遍,包括各個實(shí)現(xiàn)ISegmenter接口的各個自分詞器等內(nèi)容。

          4. 進(jìn)行詞云展示

          詞云展示可以使用 Kibana 自帶的詞云 Dashboard,或者比較熱門的 WordCloud。自己測試可以使用線上的微詞云快速便捷查看詞云效果:導(dǎo)入兩列的 XLS 文件即可,左側(cè)控制欄也可以對形狀字體等進(jìn)行配置美化。

          微詞云使用方式

          展示效果如下圖所示:

          微詞云效果圖

          5. 總結(jié)

          本文主要通過 IK 分詞器實(shí)現(xiàn)了詞頻統(tǒng)計(jì)功能,用于詞云的展示,不僅僅適用于 ES,任何數(shù)據(jù)源文檔都可以進(jìn)行詞頻統(tǒng)計(jì)。

          但是功能比較基礎(chǔ),感興趣的同學(xué)可以實(shí)現(xiàn)一下詞排序方式變更(tf/idf)、詞性標(biāo)注、實(shí)體識別和情感分析等功能;IK 分詞器較為局限,需要使用 HanLP(自帶詞性標(biāo)注)等更高級的分詞器以及 NLP 相關(guān)知識來輔助,也可以參考百度 AI 的詞法分析模塊。

          作者:caster(Elastic 認(rèn)證工程師)

          作者博客:https://www.jianshu.com/u/cc7ee7454afc

          審核:銘毅天下

          說明

          上個月,死磕 Elasticsearch 知識星球搞了:“群智涌現(xiàn)”杯輸出倒逼輸入——Elastic干貨輸出活動。

          后續(xù)會不定期逐步推出系列文章,目的:以文會友,“輸出倒逼輸入”。

          推薦

          1、重磅 | 死磕 Elasticsearch 方法論認(rèn)知清單(2021年國慶更新版)
          2Elasticsearch 7.X 進(jìn)階實(shí)戰(zhàn)私訓(xùn)課(口碑不錯)

          短時間快習(xí)得多干貨!

          已帶領(lǐng)75位球友通過 Elastic 官方認(rèn)證!


          比同事搶先一步學(xué)習(xí)進(jìn)階干貨
          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  自拍偷拍成人在线 | 操逼操逼操逼操逼操逼操逼操逼操逼 | 国产1区在线观看 | 欧美日逼大片 | 亚洲精品乱码久久久久蜜桃网站 |