美文网首页我爱编程
拼音分词与输入距离总结

拼音分词与输入距离总结

作者: 秃尾巴鸡开飞机蚍蜉撼大树 | 来源:发表于2018-04-13 14:23 被阅读0次

    总结下拼音搜索的常见做法。

    主要功能:
    基于字典分词。
    尽量消除歧义词避免分错。
    忽略单个拼音,原业务单个拼音可以当做简拼处理。
    判断一个字符串是否是拼音,’aaao’ 不认为是拼音,原因是忽略单个拼音。(可修正,在判断长度上>1去掉)

    分析:
    yuegaofenghei =>最短分词会忽略 e
    youerjizhen=>最长会忽略er。
    基于上面两种情况,进行merge,取交集合并。
    便会得到正确的分词。

    输入距离算法:
    输入距离,不单单是一种编辑距离,也不是相似性。
    例如:

    糖尿病 =>与糖尿尿病
    编辑距离与汉明距离都认为只差一个(汉明距离是hash化,局部敏感这里只是说明业务原理)

    余弦相似,无法判断,因为这只是一个词,无法算距离。
    事实上:糖尿病肾病,应该是预期提示,而 ‘糖x尿x病’ 无论x在哪都不应该排序在前。(本业务忽略这个情况,只是简单处理,建议加权差字数字为2 up n(字数)。)
    算法实现原理,定义期望因子为2,即:期望前驱出现优先,后驱,加快减少。
    简单根据指数,对数原理,进行log化,与指数化加权。

    实现效果,满足业务需求,而且极大的方便了输入排序。
    Hacknews:
    热度排序(略)设因子为1.8 ,即:过一天的衰减率为100-1,若要减缓减少重力因子即可,具体需要概率算法。

    代码:
    package com.hm.apollo.framework.utils;
    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    /**

    • Created by ant_shake_tree on 16/3/28.
      /
      public class Utils {
      private Utils cons = new Utils();
      public static String replaceBlank(String str) {
      String dest = "";
      if (str != null) {
      Pattern p = Pattern.compile("\s+|\t|\r|\n|\+|-|&|\||!|\(|\)|\{|\}|\[|\]|"|~|\
      |\?|\^");
      Matcher m = p.matcher(str);
      dest = m.replaceAll("");
      }
      //+ - && || ! ( ) { } [ ] ^ " ~ * ? :
      return dest;
      }
      // public static void main(String[] args){
      // System.out.println(Utils.replaceBlank("撒地方sad^fa \t +-&&|!(){}[]" " +
      // "ssa ~fas*?dfdf"));
      // }
    /**
     * 修改敏感字符编码
     *
     * @param value
     * @return
     */
    public static String queryEncode(String value) {
        String re[][] = {{"\\(", "\\\\\\\\\\("},
                {"\\)", "\\\\\\);"},
                {"-", "\\-"}
        };
        for (int i = 0; i < re.length; i++) {
            value = value.replaceAll(re[i][0], re[i][1]);
        }
        return value;
    }
    /**
     * 验证汉字为true
     *
     * @param s
     * @return
     */
    public static boolean isLetterorDigit(String s) {
        if (s.equals("") || s == null) {
            return false;
        }
        for (int i = 0; i < s.length(); i++) {
            if (!Character.isLetterOrDigit(s.charAt(i))) {
                // if (!Character.isLetter(s.charAt(i))){
                return false;
            }
        }
        // Character.isJavaLetter()
        return true;
    }
    /**
     * 马晓超
     * 如果前驱匹配log函数
     * 后驱匹配长度差
     * 乱序 指数匹配
     *
     * @param base
     * @param str2
     * @return
     */
    public static double shuruDistance(String base, String str2) {
        if (base.equals(str2)) return 0;
        if (str2.contains(base) && str2.startsWith(base)) {
            return Math.max(Math.log(Math.abs(base.length() - str2.length())), 0.5);
        }
        if (str2.contains(base)) {
            return Math.abs(base.length() - str2.length());
        }
        return Math.pow(2, Math.abs(base.length() - str2.length()));
    }
    public static List<String> merge(List<String> list) {
        List<String> cp = new ArrayList<>(list);
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (list.get(i).length() >= list.get(j).length()) {
                    if (list.get(i).contains(list.get(j))) {
                        cp.remove(list.get(j));
                    }
                } else {
                    if (list.get(j).contains(list.get(i))) {
                        cp.remove(list.get(i));
                    }
                }
            }
        }
        return cp;
    }
    public static void main(String[] args) {
        List<String> getp = getPinyin("aaao");
        System.out.println(isPinyin("youerjiz"));
        System.out.println(isPinyin("aaao"));
        System.out.println(isPinyin("youerjiz"));
        System.out.println(isPinyin("youerjiz"));
    }
    /**
     * 分词,全组合分词
     */
    public static List<String> fullAssembly(String sentense) {
        List<String> stringArrayList = new ArrayList<>();
        for (int beginIndex = 0; beginIndex < sentense.length(); beginIndex++) {
            for (int endIndex = beginIndex + 1; endIndex <= sentense.length(); endIndex++) {
                String kws = sentense.substring(beginIndex, endIndex);
                if ((endIndex - beginIndex) == 1) continue;
                if (getPinyinMap().containsKey(kws)) {
                    stringArrayList.add(kws);
                } else {
                    stringArrayList.add(kws);
                }
            }
        }
        return stringArrayList;
    }
    /***
     * 拼音分词
     */
    public static List<String> getPinyin(String pinyin) {
        if (!isAlpha(pinyin)) return Lists.newArrayList();
        if (pinyin.length() < 2) return Lists.newArrayList();
        final List<String> longp = Lists.newArrayList();
        final List<String> storp = Lists.newArrayList();
        int len = 0;
        int longlen = 0;
        for (int i = 0; i < pinyin.length(); i++) {
            StringBuffer str = new StringBuffer();
            int j = i;
            for (; j < pinyin.length(); j++) {
                if (!isAlphaChar(pinyin.charAt(j))) {
                    continue;
                }
                str.append(pinyin.charAt(j));
                if (str.length() > 1 && getPinyinMap().containsKey(str.toString())) {
                    len += str.length();
                    storp.add(str.toString());
                    i = j;
                    break;
                }
            }
        }
        int index = 0;
        int jiequ = 0;
        //最大切分
        for (int i = 0; i < pinyin.length(); i++) {
            StringBuffer str = new StringBuffer();
            for (int j = i; j < pinyin.length(); j++) {
                if (!isAlphaChar(pinyin.charAt(j))) {
                    continue;
                }
                str.append(pinyin.charAt(j));
                index++;
                if (str.length() > 1 && getPinyinMap().containsKey(str.toString())) {
                    i = j;
                    jiequ = index;
                    if (j == pinyin.length() - 1) {
                        if (!"".equals(str.toString())) {
                            longp.add(str.toString());
                            longlen += str.length();
                        }
                        break;
                    }
                }
                if ((str.length() >= 5 && !getPinyinMap().containsKey(str.toString())) || (j == pinyin.length() - 1)) {
                    String sub=str.toString().substring(0, jiequ);
                    if (!"".equals(sub)) {
                        longp.add(sub);
                        longlen += sub.length();
                    }
                    index = 0;
                    jiequ = 0;
                    break;
                }
            }
        }
        if(storp.size()==0||longp.size()==0)return storp;
        if (longlen == pinyin.length()) {
            return longp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
        } else if (len < pinyin.length()) {
            mergePinyinList(storp,longp,len,pinyin.length());
            return storp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
        }
        return longp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
    }
    public static boolean isAlpha(String charSequence) {
        if (charSequence == null) return false;
        for (char c : charSequence.toCharArray()) {
            if (c == '-') continue;
            if (!isAlphaChar(c)) {
                return false;
            }
        }
        return true;
    }
    public static boolean isAlphaChar(char c) {
        if (((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) return true;
        else return false;
    }
    /**
     * 判断是否是拼音
     *
     * @param keyworld
     * @return
     */
    public static boolean isPinyin(String keyworld) {
        if (keyworld.length() <= 2) {
            return false;
        }
        List<String> list = getPinyin(keyworld);
        if (list.size() > 0) {
            int len = 0;
            for (String k : list) {
                len += k.length();
            }
            if (len == keyworld.length()) {
                return true;
            }
            //排除错误
            if ((keyworld.length() - len) == 1 && keyworld.startsWith(list.get(0))) return true;
        }
        return false;
    }
    private static void mergePinyinList(List<String> shortPinyin,List<String> longPinyin,int lenS,int len){
        if(lenS<len){
            for(int i=shortPinyin.size()-1;i>=0;i--){
                String shortStr=shortPinyin.get(i);
                for(int j=longPinyin.size()-1;j>=0;j--) {
                    String s = longPinyin.get(j);
                    if (s.contains(shortStr)) {
                        lenS+=s.length()-shortStr.length();
                        shortPinyin.remove(shortStr);
                        shortPinyin.add(i,s);
                        longPinyin.remove(s);
                    }
                    if(lenS>=len)
                        break;
                }
            }
        }
    }
    private static final Map<String, Integer> stringIntegerMap = Stream.of("a", "ai", "an", "ang", "ao", "ba", "bai",
            "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu", "ca",
            "cai", "can", "cang", "cao", "ce", "cen", "ceng", "cha", "chai", "chan", "chang", "chao", "che", "chen",
            "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci",
            "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", "den",
            "deng", "di", "dia", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo",
            "e", "en", "eng", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fiao", "fo", "fou", "fu", "ga", "gai",
            "gan", "gang", "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang",
            "gui", "gun", "guo", "ha", "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu",
            "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin",
            "jing", "jiong", "jiu", "ju", "juan", "jue", "ka", "kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong",
            "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le",
            "lei", "leng", "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "lo", "long", "lou", "lu",
            "luan", "lun", "luo", "lv", "lve", "ma", "mai", "man", "mang", "mao", "me", "mei", "men", "meng", "mi",
            "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", "nan", "nang", "nao", "ne",
            "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nou", "nu",
            "nuan", "nun", "nuo", "nv", "nve", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi",
            "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
            "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong",
            "rou", "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng",
            "sha", "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua",
            "shuai", "shuan", "shuang", "shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo",
            "ta", "tai", "tan", "tang", "tao", "te", "tei", "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou",
            "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi",
            "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya",
            "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za",
            "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", "zhe",
            "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun",
            "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo", "walker")
            .collect(Collectors.toMap(s -> s, s -> 1));
    /**
     * 拼音字典
     *
     * @return
     */
    public static Map<String, Integer> getPinyinMap() {
        return stringIntegerMap;
    }
    

    }

    相关文章

      网友评论

        本文标题:拼音分词与输入距离总结

        本文链接:https://www.haomeiwen.com/subject/mgmckftx.html