jieba java 磁性_jieba分詞的應用(java)

在上一篇說的猜你喜歡功能中,又加了新的需求,需要對關鍵詞進行分詞,擴大推薦文章的范圍,這樣能夠拓展用戶的喜歡范圍,這時候我就想到可以用jieba分詞對中文進行分詞,同樣的需要去官網下載源碼,這樣方便自己對源碼的修改以達到自己的目的。這里,我需要判斷切分出來的詞是否是無意義的詞,就需要對切出來的詞進行篩選,這時候,jieba分詞的一個屬性就體現出它的強大之處了,jieba分詞會將切分出來的詞進行詞性的定義,我可以通過對於jieba分此后詞的詞性進行判斷,篩選出名詞,去掉無用的連接詞,形容詞等其他詞性的詞來達到我的分詞目的。下面是對源碼進行修改的部分。(大家也可以根據自己的需要,暴露原來隱藏的屬性來實現自己的功能。)

/**

*在jieba分詞的SegToken.java中對SegToken類增加一個成員變量properties來存儲單詞的詞性

**/

package com.huaban.analysis.jieba;

public class SegToken {

public String word;

public int startOffset;

public int endOffset;

public String properties;

public SegToken(String word, int startOffset, int endOffset, String properties) {

this.word = word;

this.startOffset = startOffset;

this.endOffset = endOffset;

this.properties = properties;

}

@Override

public String toString() {

return "[" + word + ", " + startOffset + ", " + endOffset + ", " + properties + "]";

}

}

將從字典文件dict.txt中讀取出來的單詞的詞性存儲到properties 的字段中

/**

*在WordDictionary.java中增加property的Map存儲word與詞性的關系。建立索引關系,增加獲取詞性的公共方法

**/

package com.huaban.analysis.jieba;

import java.io.BufferedReader;

import java.nio.file.DirectoryStream;

import java.nio.file.Files;

import java.nio.file.Path;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.nio.charset.Charset;

import java.nio.charset.StandardCharsets;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Locale;

import java.util.Map;

import java.util.Map.Entry;

import java.util.Set;

public class WordDictionary {

private static WordDictionary singleton;

private static final String MAIN_DICT = "/dict.txt";

private static String USER_DICT_SUFFIX = ".dict";

public final Map freqs = new HashMap();

public final Map property = new HashMap();

public final Set loadedPath = new HashSet();

private Double minFreq = Double.MAX_VALUE;

private Double total = 0.0;

private DictSegment _dict;

private WordDictionary() {

this.loadDict();

}

public static WordDictionary getInstance() {

if (singleton == null) {

synchronized (WordDictionary.class) {

if (singleton == null) {

singleton = new WordDictionary();

return singleton;

}

}

}

return singleton;

}

/**

* for ES to initialize the user dictionary.

*

*@param configFile

*/

public void init(Path configFile) {

String abspath = configFile.toAbsolutePath().toString();

System.out.println("initialize user dictionary:" + abspath);

synchronized (WordDictionary.class) {

if (loadedPath.contains(abspath))

return;

DirectoryStream stream;

try {

stream = Files.newDirectoryStream(configFile, String.format(Locale.getDefault(), "*%s", USER_DICT_SUFFIX));

for (Path path: stream){

System.err.println(String.format(Locale.getDefault(), "loading dict %s", path.toString()));

singleton.loadUserDict(path);

}

loadedPath.add(abspath);

} catch (IOException e) {

// TODO Auto-generated catch block

// e.printStackTrace();

System.err.println(String.format(Locale.getDefault(), "%s: load user dict failure!", configFile.toString()));

}

}

}

/**

* let user just use their own dict instead of the default dict

*/

public void resetDict(){

_dict = new DictSegment((char) 0);

freqs.clear();

}

public void loadDict() {

_dict = new DictSegment((char) 0);

InputStream is = this.getClass().getResourceAsStream(MAIN_DICT);

try {

BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));

long s = System.currentTimeMillis();

while (br.ready()) {

String line = br.readLine();

String[] tokens = line.split("[\t ]+");

if (tokens.length < 2)

continue;

String word = tokens[0];

String properties = "";

double freq = Double.valueOf(tokens[1]);

if(tokens.length == 3)

properties = tokens[2];

total += freq;

word = addWord(word);

freqs.put(word, freq);

property.put(word, properties);//存儲單詞與詞性的索引關系

}

// normalize

for (Entry entry : freqs.entrySet()) {

entry.setValue((Math.log(entry.getValue() / total)));

minFreq = Math.min(entry.getValue(), minFreq);

}

System.out.println(String.format(Locale.getDefault(), "main dict load finished, time elapsed %d ms",

System.currentTimeMillis() - s));

}

catch (IOException e) {

System.err.println(String.format(Locale.getDefault(), "%s load failure!", MAIN_DICT));

}

finally {

try {

if (null != is)

is.close();

}

catch (IOException e) {

System.err.println(String.format(Locale.getDefault(), "%s close failure!", MAIN_DICT));

}

}

}

private String addWord(String word) {

if (null != word && !"".equals(word.trim())) {

String key = word.trim().toLowerCase(Locale.getDefault());

_dict.fillSegment(key.toCharArray());

return key;

}

else

return null;

}

public void loadUserDict(Path userDict) {

loadUserDict(userDict, StandardCharsets.UTF_8);

}

public void loadUserDict(Path userDict, Charset charset) {

try {

BufferedReader br = Files.newBufferedReader(userDict, charset);

long s = System.currentTimeMillis();

int count = 0;

while (br.ready()) {

String line = br.readLine();

String[] tokens = line.split("[\t ]+");

if (tokens.length < 1) {

// Ignore empty line

continue;

}

String word = tokens[0];

double freq = 3.0d;

String properties = "";

if (tokens.length == 2)

freq = Double.valueOf(tokens[1]);

if(tokens.length == 3)

properties = tokens[2];//獲取單詞的詞性,存入map中

word = addWord(word);

freqs.put(word, Math.log(freq / total));

property.put(word, properties);

count++;

}

System.out.println(String.format(Locale.getDefault(), "user dict %s load finished, tot words:%d, time elapsed:%dms", userDict.toString(), count, System.currentTimeMillis() - s));

br.close();

}

catch (IOException e) {

System.err.println(String.format(Locale.getDefault(), "%s: load user dict failure!", userDict.toString()));

}

}

public DictSegment getTrie() {

return this._dict;

}

public boolean containsWord(String word) {

return freqs.containsKey(word);

}

public String getProperties(String word){//通過單詞獲取單詞的詞性

if(containsWord(word))

return property.get(word);

else

return "";

}

public Double getFreq(String key) {

if (containsWord(key))

return freqs.get(key);

else

return minFreq;

}

}

將詞性存儲到SegToken的成員變量中,方便生成和調取。

/**

*在JiebaSegmenter.java中生成每個切分詞的SegToken對象進行存儲,方便使用

**/

public List process(String paragraph, SegMode mode) {//對paragraphs進行切分,存儲到SegToken中

List tokens = new ArrayList();

StringBuilder sb = new StringBuilder();

int offset = 0;

for (int i = 0; i < paragraph.length(); ++i) {

char ch = CharacterUtil.regularize(paragraph.charAt(i));

if (CharacterUtil.ccFind(ch))

sb.append(ch);

else {

if (sb.length() > 0) {

// process

if (mode == SegMode.SEARCH) {

for (String word : sentenceProcess(sb.toString())) {

tokens.add(new SegToken(word, offset, offset += word.length(), wordDict.getProperties(word)));//將詞性存儲進去

}

}

else {

for (String token : sentenceProcess(sb.toString())) {

if (token.length() > 2) {

String gram2;

int j = 0;

for (; j < token.length() - 1; ++j) {

gram2 = token.substring(j, j + 2);

if (wordDict.containsWord(gram2))

tokens.add(new SegToken(gram2, offset + j, offset + j + 2, wordDict.getProperties(gram2)));

}

}

if (token.length() > 3) {

String gram3;

int j = 0;

for (; j < token.length() - 2; ++j) {

gram3 = token.substring(j, j + 3);

if (wordDict.containsWord(gram3))

tokens.add(new SegToken(gram3, offset + j, offset + j + 3, wordDict.getProperties(gram3)));

}

}

tokens.add(new SegToken(token, offset, offset += token.length(), wordDict.getProperties(token)));

}

}

sb = new StringBuilder();

offset = i;

}

if (wordDict.containsWord(paragraph.substring(i, i + 1)))

tokens.add(new SegToken(paragraph.substring(i, i + 1), offset, ++offset, wordDict.getProperties(paragraph.substring(i, i + 1))));

else

tokens.add(new SegToken(paragraph.substring(i, i + 1), offset, ++offset, wordDict.getProperties(paragraph.substring(i, i + 1))));

}

}

if (sb.length() > 0)

if (mode == SegMode.SEARCH) {

for (String token : sentenceProcess(sb.toString())) {

tokens.add(new SegToken(token, offset, offset += token.length(), wordDict.getProperties(token)));

}

}

else {

for (String token : sentenceProcess(sb.toString())) {

if (token.length() > 2) {

String gram2;

int j = 0;

for (; j < token.length() - 1; ++j) {

gram2 = token.substring(j, j + 2);

if (wordDict.containsWord(gram2))

tokens.add(new SegToken(gram2, offset + j, offset + j + 2, wordDict.getProperties(gram2)));

}

}

if (token.length() > 3) {

String gram3;

int j = 0;

for (; j < token.length() - 2; ++j) {

gram3 = token.substring(j, j + 3);

if (wordDict.containsWord(gram3))

tokens.add(new SegToken(gram3, offset + j, offset + j + 3, wordDict.getProperties(gram3)));

}

}

tokens.add(new SegToken(token, offset, offset += token.length(), wordDict.getProperties(token)));

}

}

return tokens;

}

然后在關鍵詞切分的方法中進行判斷,選擇所需要詞性的word即可

//對關鍵詞進行結巴keyword分詞

for (String sentence : keyword_list) {

List tokens = segmenter.process(sentence, SegMode.SEARCH);

for(SegToken s : tokens)

if(s.word.length() > 1)

keyword += " "+s.word;

}

keyword_list = keyword.split("[,;\\s'\\*\\+|\\^]+");

Set keywordList = new LinkedHashSet(Arrays.asList(keyword_list));//用set是為了去除文章的重復

到此完成新需求的實現。與大家共勉~

最后附上jieba分詞的此行類別及表示方法:

Ag

形語素

形容詞性語素。形容詞代碼為 a,語素代碼g前面置以A。

a

形容詞

取英語形容詞 adjective的第1個字母。

ad

副形詞

直接作狀語的形容詞。形容詞代碼 a和副詞代碼d並在一起。

an

名形詞

具有名詞功能的形容詞。形容詞代碼 a和名詞代碼n並在一起。

b

區別詞

取漢字“別”的聲母。

c

連詞

取英語連詞 conjunction的第1個字母。

dg

副語素

副詞性語素。副詞代碼為 d,語素代碼g前面置以D。

d

副詞

取 adverb的第2個字母,因其第1個字母已用於形容詞。

e

嘆詞

取英語嘆詞 exclamation的第1個字母。

f

方位詞

取漢字“方”

g

語素

絕大多數語素都能作為合成詞的“詞根”,取漢字“根”的聲母。

h

前接成分

取英語 head的第1個字母。

i

成語

取英語成語 idiom的第1個字母。

j

簡稱略語

取漢字“簡”的聲母。

k

后接成分

l

習用語

習用語尚未成為成語,有點“臨時性”,取“臨”的聲母。

m

數詞

取英語 numeral的第3個字母,n,u已有他用。

Ng

名語素

名詞性語素。名詞代碼為 n,語素代碼g前面置以N。

n

名詞

取英語名詞 noun的第1個字母。

nr

人名

名詞代碼 n和“人(ren)”的聲母並在一起。

ns

地名

名詞代碼 n和處所詞代碼s並在一起。

nt

機構團體

“團”的聲母為 t,名詞代碼n和t並在一起。

nz

其他專名

“專”的聲母的第 1個字母為z,名詞代碼n和z並在一起。

o

擬聲詞

取英語擬聲詞 onomatopoeia的第1個字母。

p

介詞

取英語介詞 prepositional的第1個字母。

q

量詞

取英語 quantity的第1個字母。

r

代詞

取英語代詞 pronoun的第2個字母,因p已用於介詞。

s

處所詞

取英語 space的第1個字母。

tg

時語素

時間詞性語素。時間詞代碼為 t,在語素的代碼g前面置以T。

t

時間詞

取英語 time的第1個字母。

u

助詞

取英語助詞 auxiliary

vg

動語素

動詞性語素。動詞代碼為 v。在語素的代碼g前面置以V。

v

動詞

取英語動詞 verb的第一個字母。

vd

副動詞

直接作狀語的動詞。動詞和副詞的代碼並在一起。

vn

名動詞

指具有名詞功能的動詞。動詞和名詞的代碼並在一起。

w

標點符號

x

非語素字

非語素字只是一個符號,字母 x通常用於代表未知數、符號。

y

語氣詞

取漢字“語”的聲母。

z

狀態詞

取漢字“狀”的聲母的前一個字母。

un

未知詞

不可識別詞及用戶自定義詞組。取英文Unkonwn首兩個字母。(非北大標准,CSW分詞中定義)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值