package ruc.irm.similarity.word.hownet2.sememe; import java.io.IOException; import java.util.Collection; /** * 刘群老师计算义原相似度的方法, 实现了SememeParser中定义的抽象方法 * * @author <a href="mailto:iamxiatian@gmail.com">夏天</a> * @organization 中国人民大学信息资源管理学院 知识工程实验室 * * @author <a href="xiat@ruc.edu.cn">xiatian</a> * @version 1.0 */ public class LiuqunSememeParser extends BaseSememeParser { /** 计算义元相似度的可调节的参数,默认为1.6 */ private final float alpha = 1.6f; public LiuqunSememeParser() throws IOException { super(); } /** * 计算两个义元之间的相似度,由于义元可能相同,计算结果为其中相似度最大者 * <br/>similarity = alpha/(distance+alpha) * * @param key1 * @param key2 * @return */ @Override public double getSimilarity(String item1, String item2) { int pos; // 如果为空串,直接返回0 if (item1 == null || item2 == null || item1.equals("") || item2.equals("")) return 0.0; String key1 = item1.trim(); String key2 = item2.trim(); // 去掉()符号 if ((key1.charAt(0) == '(') && (key1.charAt(key1.length() - 1) == ')')) { if (key2.charAt(0) == '(' && key2.charAt(key2.length() - 1) == ')') { key1 = key1.substring(1, key1.length() - 1); key2 = key2.substring(1, key2.length() - 1); } else { return 0.0; } } // 处理关系义元,即x=y的情况 if ((pos = key1.indexOf('=')) > 0) { int pos2 = key2.indexOf('='); // 如果是关系义元,则判断前面部分是否相同,如果相同,则转为计算后面部分的相似度,否则为0 if ((pos == pos2) && key1.substring(0, pos).equals(key2.substring(0, pos2))) { key1 = key1.substring(pos + 1); key2 = key2.substring(pos2 + 1); } else { return 0.0; } } // 处理符号义元,即前面有特殊符号的义元 String symbol1 = key1.substring(0, 1); String symbol2 = key2.substring(0, 1); for (int i = 0; i < Symbol_Descriptions.length; i++) { if (symbol1.equals(Symbol_Descriptions[i][0])) { if (symbol1.equals(symbol2)) { key1 = item1.substring(1); key2 = item2.substring(1); break; } else { return 0.0; // 如果不是同一关系符号,则相似度直接返回0 } } } if ((pos = key1.indexOf("|")) >= 0) { key1 = key1.substring(pos + 1); } if ((pos = key2.indexOf("|")) >= 0) { key2 = key2.substring(pos + 1); } int distance = getMinDistance(key1, key2); return alpha / (distance + alpha); } /** * 根据汉语定义计算义原之间的距离,Integer.MAX_VALUE代表两个义元之间的距离为无穷大,由于可能多个义元有相同的汉语词语, * 故计算结果为其中距离最小者 * * @param key1 * @param key2 * @return */ public int getMinDistance(String sememe1, String sememe2) { int distance = Integer.MAX_VALUE; // 如果两个字符串相等,直接返回距离为0 if (sememe1.equals(sememe2)) { return 0; } Collection<String> sememeIds1 = SEMEMES.get(sememe1); Collection<String> sememeIds2 = SEMEMES.get(sememe2); // 如果sememe1或者sememe2不是义元,则返回无穷大 if (sememeIds1.size() == 0 || sememeIds1.size() == 0) { return Integer.MAX_VALUE; } for(String id1:sememeIds1){ for(String id2:sememeIds2){ int d = getDistance(id1, id2); if(d<distance){ distance = d; } } } return distance; } /** * 根据义原的具有层次的Id获取两个义原之间的语义距离 * @param id1 * @param id2 * @return */ int getDistance(String id1, String id2) { // 两个Id相同的位置终止地方 int position = 0; String[] array1 = id1.split("-"); String[] array2 = id2.split("-"); for (position = 0; position < array1.length && position < array2.length; position++) { if (!array1[position].equals(array2[position])) { return array1.length + array2.length - position - position; } } if (array1.length == array2.length) { return 0; } else if (array1.length == position) { return array2.length - position; } else { return array1.length - position; } } }