您的位置:首页 > 其它

NLP: 中文分词---正向匹配 (Forward Matching)

2014-07-11 17:14 295 查看
在采用FMM (正向最大匹配) 进行中文分词的时候, 可能会存在比较多的交集歧义, 这个时候为了解决交集歧义的问题, 可以采用 FM (Forwar Matching, 正向匹配) 进行中文分词, 正向匹配会在最大匹配的路径上查找所有可能成词的term(这里所有可能成词的term的意思是在构建索引的时候所有切分出来的词, 因为不是路径上的所有节点都会是切分成的词)。

http://blog.csdn.net/watkinsong/article/details/37696389  这个文章中给出了FMM(正向最大匹配) 的算法实现。

算法描述如下图给出, 下面的图比较多, 但是描述的比较详细。 图后给出代码实现。

FM算法最大的问题就是切分的结果太琐碎, 因为在一次FMM(正向最大匹配)的过程中, 路径上所有是term的节点都会作为一个切分结果。 这样做的好处就是可以减少交集歧义的影响。























 接下来根据算法给出代码。 代码假设已经存在索引, 并且索引采用trie树进行保存。

仍然是JS代码。。。

var lunr = require("./lunr.js")
var idxdata = require("./idx.json")

var idx = lunr.Index.load(idxdata)
var ii = idx.tokenStore

var query1 = "中国人民银行指出我国最近经济不景气"
var query2 = "习近平今日出席了中央气象台的联欢晚会"
var query3 = "中国银行今日出台了最新的贷款政策"
var query5 = "全部门"
var query6 = "互联网金宝"
var query7 = "上下级别"
var query8 = "确定期"
var query9 = "引领土完整"

query = query6
var result = tokenizer(ii.root, query)
console.log(result)

/* tokenizer */
function tokenizer(root, str) {
if ( root == null || root == undefined ) return []
if ( str == null || str == undefined || str.length == 0 ) return []

var out = []
while ( str.length > 0 ) {
var ret = forwardMatching(root, str)
out = out.concat(ret)
str = str.slice(1)
}

return out
}

/* FM, this will return all the possible terms in along the longest search path */
function forwardMatching(root, str) {
if ( root == null || root == undefined ) return
if ( str == null || str == undefined || str.length == 0 ) return

var out = []
var matches = ""
var currentNode = root
for( var i = 0; i < str.length; i++ ) {
if (str[i] in currentNode ) {
matches += str[i]
currentNode = currentNode[str[i]]
docs = currentNode.docs || {}
if ( Object.keys(docs).length ) {
// if current node is a term, add this term as a segment piece
out.push(matches)
}
} else {
if ( matches.length == 0 ) {
// un-board word found
out.push(str[i])
}
break
}
}

return out
}

function getAmbiguiousLength(root, str, word_length) {
var i = 1
while ( i < word_length && i < str.length ) {
var wid = tokenize(root, str.slice(i))
wid = wid[0]
var length = wid.length
if ( word_length < i + length ) word_length = i + length
//console.log("i = " + i + ",length=" + wid.length + ", wid :" + wid + ", word_length : " + word_length)
i += 1
}

return word_length
}

测试: 
query: "互联网金宝"

切分结果: [ '互联网', '网', '网金宝', '金', '宝' ]

这里, 因为在切分 “联网金宝”子句时, “联” 在索引中出现, 但是并不是一个term, 所以跳过“联”, 进行下一次切分“网金宝”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息