NLP: 中文分词算法---交集歧义检测 (cross ambiguity detect)

在 文章 http://blog.csdn.net/watkinsong/article/details/37697451 里面提到的FM中文分词算法中, 最大的问题就是将用户的query切分的太碎, 切分太碎也会对检索结果造成一定的影响。

这里, 可以采用FMM算法进行切分, 首先切分出最大的正向匹配, 然后进行交集歧义检测, 如果检测到存在交集歧义, 那么对可能存在歧义的一段文字进行FM切分, 获取所有的可能切分结果; 然后对剩下的query子句重复进行FMM切分, 直到query == null

例如, 用户查询 query = 123456789, 假设首先FMM切分到了“123”, 交集歧义检测长度为6, 这时候存在歧义, 那么对“123456”进行FM切分, 获取“123456”的所有的切分可能, 然后再对剩下的子句“789”循环进行FMM切分。

交集歧义检测算法描述:

假设 query = "互联网金宝", 首先进行FMM, 切分出“互联网”, 然后我们要检测是否存在交集歧义, 将“互联网”的长度作为输入, 这里我们使用变量word_len表示FMM切分结果的长度, 这里word_len = 3; 同时将query的子句“联网金宝”作为输入, 进行以下迭代:

如此循环下去, 循环结束的条件是 i < word_length && i < str.length

1.

对输入的 str = "联网金宝" 进行FMM切分, 获取切分后长度, 假设为“联网”, len = 2

如果此时 word_length < i + len, 则 word_length = i + length

此时, i = 1, len = 2, word_len = 3

str = str.slice(1)

2.

对 str = "网金宝" 进行FMM切分, 获取切分后长度, 假设为“网金宝”, len = 3

如果此时 word_length < i + len, 则 word_length = i + length, 这里,  i + len = 5, i + len > word_len, 设置word_len = 5

此时, i = 2, len = 3, word_len = 5

str = str.slice(1)

3.

此时 i =3, str.length 为, 循环条件不成立, 退出迭代。

代码实现:

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 query4 = "习近平的中央气象台"
var query5 = "全部门"
var query6 = "互联网金宝"
var query7 = "上下级别"
var query8 = "互联网中国人民银行"
var query9 = "引领土完整"

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

/* tokenizer */
/* do FMM first and then detect ambiguity, if ambiguity detected, do FM again*/
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 = matchLongest(root, str)
	var ambiguityLength = getAmbiguiousLength(root, str, ret.length)
	console.log("FMM: " + ret + ", ambituity length: " + ambiguityLength)
	if ( ret.length >= ambiguityLength) {
	    out.push(ret)
	} else {
	  console.log("ambiguity detected!!!")
	  var ambiguityStr = str.substr(0, ambiguityLength)
	  console.log("do FM again for ambiguity piece: " + ambiguityStr)
	  var ret = ambiguityTokenizer(root, ambiguityStr)
	  out = out.concat(ret)
	}
    str = str.slice(ambiguityLength)
  }

  return out
}

function matchLongest(root, str) {
  if ( root == null || root == undefined ) return
  if ( str == null || str == undefined || str.length == 0 ) return

  var maxMatch = ""
  var currentNode = root
  for( var i = 0; i < str.length; i++ ) {
    if (str[i] in currentNode ) {
      maxMatch += str[i]
      currentNode = currentNode[str[i]]
    } else {
      if ( maxMatch.length == 0 ) maxMatch = str[i] // un-board word found
      break
    }
  }

  return maxMatch
}

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

  var out = []
  var query = str
  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 ) {
		out.push(matches)
	  }
    } else {
	  if ( matches.length == 0 ) {
	    // un-board word found
		// do not add un-board word, because when doing search, un-board word is bad and will affect the search results
		//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 = matchLongest(root, str.slice(i))
    var length = wid.length
    if ( word_length < i + length ) word_length = i + length
    i += 1
  }

  return word_length
}

测试:

query: "互联网金宝"

结果:

FMM: 互联网, ambituity length: 5
ambiguity detected!!!
do FM again for ambiguity piece: 互联网金宝
[ '互联网', '网', '网金宝', '金', '宝' ]

query: "互联网中国人民银行"

结果:

FMM: 互联网, ambituity length: 3
FMM: 中国人民银行, ambituity length: 6
[ '互联网', '中国人民银行' ]

NLP: 中文分词算法---交集歧义检测 (cross ambiguity detect)

时间: 2024-10-17 07:57:52

NLP: 中文分词算法---交集歧义检测 (cross ambiguity detect)的相关文章

NLP: 中文分词算法--正向最大匹配 Forward Maximum Matching

最近接触NLP中文分词, 在lunr.js的基础上, 实现了中文的最大正向匹配分词. 某些情况下, 我们在服务器端进行中文文本分词可以使用完整的基于mmseg算法的分词模块, 例如nodejieba, node-segment, 盘古分词等等,  但是在客户端环境下, 我们不能使用这些复杂的分词算法进行分词, 这个时候可以根据已经生成的索引进行简单的客户端分词, 就是所说的FMM (Forward Maximum Matching, 正向最大匹配), 有时候也可以使用正向匹配. 在做FMM的时候

中文分词算法综述

英文文本词与词之间以空格分隔,方便计算机识别,但是中文以字为单位,句子所有字连起来才能表达一个完整的意思.如英文"I am writing a blog",英文词与词之间有空格进行隔开,而对应的中文"我在写博客",所有的词连在一起,计算机能很容易的识别"blog"是一个单词,而很难知道"博"."客"是一个词,因此对中文文本序列进行切分的过程称为"分词".中文分词算法是自然语言处理的基础,

机器学习基础——一文讲懂中文分词算法

在前文当中,我们介绍了搜索引擎的大致原理.有错过或者不熟悉的同学,可以点击下方的链接回顾一下前文的内容. ML基础--搜索引擎基本原理 在介绍爬虫部分的时候,我们知道,爬虫在爬取到网页的内容之后,会先进行一些处理.首先要做的就是过滤掉HTML当中的各种标签信息,只保留最原生的网页内容.之后,程序会对这些文本内容提取关键词. 今天我们就来讲讲关键词提取当中最重要的一个部分--中文分词. 在世界上众多的语言当中,中文算是比较特殊的一种.许多语言自带分词信息,比如英文,机器学习写作machine le

在Hadoop上运行基于RMM中文分词算法的MapReduce程序

原文:http://xiaoxia.org/2011/12/18/map-reduce-program-of-rmm-word-count-on-hadoop/ 在Hadoop上运行基于RMM中文分词算法的MapReduce程序 23条回复 我知道这个文章标题很“学术”化,很俗,让人看起来是一篇很牛B或者很装逼的论文!其实不然,只是一份普通的实验报告,同时本文也不对RMM中文分词算法进行研究.这个实验报告是我做高性能计算课程的实验里提交的.所以,下面的内容是从我的实验报告里摘录出来的,当作是我学

Mmseg中文分词算法解析

@author linjiexing 开发中文搜索和中文词库语义自己主动识别的时候,我採用都是基于mmseg中文分词算法开发的Jcseg开源project.使用场景涉及搜索索引创建时的中文分词.新词发现的中文分词.语义词向量空间构建过程的中文分词和文章特征向量提取前的中文分词等,整体使用下来,感觉jcseg是一个非常优秀的开源中文分词工具,并且可配置和开源的情况下,能够满足非常多场景的中文分词逻辑.本文先把jcseg使用到最主要的mmseg算法解析一下. 1. 中文分词算法之争 在分析mmseg

NLP︱中文分词技术小结、几大分词引擎的介绍与比较

笔者想说:觉得英文与中文分词有很大的区别,毕竟中文的表达方式跟英语有很大区别,而且语言组合形式丰富,如果把国外的内容强行搬过来用,不一样是最好的.所以这边看到有几家大牛都在中文分词以及NLP上越走越远.哈工大以及北大的张华平教授(NLPIR)的研究成果非常棒! 但是商业应用的过程中存在的以下的问题: 1.是否先利用开源的分词平台进行分词后,再自己写一些算法进行未登录词.歧义词的识别? 2.或者直接调用下文介绍的分词引擎来进行分词呢?缴费使用固然很棒,但是是否值得? ---------------

中文分词算法 之 基于词典的全切分算法

在使用 基于词典 的分词方法的时候,如果我们解决了下面4个问题: 1.如何把一句话中所有的词找出来呢?只要词典中有就一定要找出来. 2.如何利用1中找出来的词组合成完整的句子?组合成的句子要和原句一样. 3.如何保证2中组合而成的句子包含了所有可能的词序? 4.如何从所有可能的词序中选择最完美的一种作为最终的分词结果? 那么我们的分词方法称之为:基于词典的全切分算法. 下面我们以一个实例来说明,比如句子:中华人民共和国. 假设词典中包含如下词: 中华人民共和国 中华人民 中华 华人 人民共和国

java中文分词算法

我想只要是学过数据库的孩纸,不管是mysql,还是sqlsever,一提到查找,本能的想到的便是like关键字,其实去转盘网(分类模式)之前也是采用这种算法,但我可以告诉大家一个很不幸的事情,like匹配其实会浪费大量的有用资源,原因这里不说了请自己想一想,我们还是直接摆事实验证. 现在用去转盘网搜:hello 找个单词,如下: http://www.quzhuanpan.com/source/search.action?q=hello&currentPage=1 翻页你会发现只要是包含hell

中文分词算法-百度面试题

题目: 给定一个字符串, 一个数组,判断这个字符串能否被分隔成字典里的一个个单词. 用动态规划算法 我面试时写的是下面的代码 public static boolean divied2(String s,String[] dict){ boolean result=false; if(s.length()==0) return true; for (int i = 0; i < dict.length; i++) { int index=s.indexOf(dict[i]); if (index