汉语拼音的模糊音扩展(用于搜索纠错)

本文介绍了一种针对拼音输入法常见问题的解决方案,通过声母和韵母互换实现模糊拼音扩展,确保用户搜索时即使输入错误也能找到相关结果。算法详细解释了扩展规则,并举例展示了如何将'liulai'扩展为多个可能的搜索词以提高搜索精度。
摘要由CSDN通过智能技术生成

    由于现在使用拼音输入法较多,很可能输入同音字而无法搜索到结果,或者由于普通话不标准(前后鼻音不分)输入了错误的拼音。例如用户想搜索”牛奶“却输入了刘来(liulai),那我们可以对liulai进行模糊音扩展,然后一起放到搜索引擎中去搜索。为了避免过度扩展曲解了用户的意图,对于扩展词需要进行排序,越少改动越排在前面(原文排在最前),越多改动越排在后面。在搜索时按照顺序赋予不同的权重。

  类似这样:

 "query": {"bool":{
         "should":[
    {"match" : { "t.py":{"query": "lanqiuxie","analyzer":"whitespace","operator":"or"  ,"boost":3}}},         
 {"match" : { "t.py":{"query": "langqiuxie","analyzer":"whitespace","operator":"or"  ,"boost":3}}}, 
 {"match" : { "t.py":{"query": "nangqiuxie","analyzer":"whitespace","operator":"or"  ,"boost":2}}}, 
 {"match" : { "t.py":{"query": "nanqiuxie","analyzer":"whitespace","operator":"or"  ,"boost":1}}}]}}}

好,现在show一下模糊拼音扩展的算法:

1.声母l和n互换

2.韵母有g和没g互换。

3.变换少的排在前面。

例如 ["liulai"] => ["liulai","liunai","niulai","niunai"]

    //汉语拼音模糊音扩展
    static public List<String> expand(String[] ss) {
        int n = ss.length;
        List<String>[] lists = new ArrayList[n];
        List<Integer> changes = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            lists[i] = expandOne(ss[i]);
            if (lists[i].size() > 1) changes.add(i);
        }
        int max = changes.size();
        if (max > 4) max = 4;
        List<String> ans = new ArrayList<>();
        for (int i = 0; i <= max; i++) {
            ans.addAll(miss(lists, changes, i, 0, 0));
        }
        return ans;
    }

   static private Map<String, String> confusingMap = new HashMap<String, String>() {{
        this.put("in", "ing");
        this.put("an", "ang");
        this.put("en", "eng");
        this.put("un", "ong");
    }};

    static private List<String> miss(List<String>[] lists, List<Integer> changes, int c, int b1, int b2) {
        List<String> list = new ArrayList<>();
        if (c > changes.size() - b2 || c < 0) return list;
        int n = lists.length;
        if (c == 0) {
            StringBuilder sb = new StringBuilder();
            for (int i = b1; i < n; i++) {
                sb.append(lists[i].get(0));
            }
            list.add(sb.toString());
        } else {
            int fc = changes.get(b2);
            StringBuilder sb = new StringBuilder();
            for (int i = b1; i < fc; i++) {
                sb.append(lists[i].get(0));
            }
            String pre = sb.toString();
            List<String> left = miss(lists, changes, c - 1, fc + 1, b2 + 1);
            for (int i = 1; i < lists[fc].size(); i++) {
                for (String s : left) {
                    list.add(pre + lists[fc].get(i) + s);
                }
            }
            pre += lists[fc].get(0);
            left = miss(lists, changes, c, fc + 1, b2 + 1);
            for (String s : left) {
                list.add(pre + s);
            }
        }
        return list;
    }

    static private List<String> expandOne(String py) {
        List<String> list = new ArrayList<>();
        list.add(py);
        if (py.equals("yang") || py.equals("yan")) return list;
        if (py.startsWith("l") || py.startsWith("n")) {
            List<String> vs = changeVowel(py.substring(1));
            String[] ln = py.startsWith("l") ? new String[]{"l", "n"}
                    : new String[]{"n", "l"};
            for (String sm : ln) {
                for (String s : vs) {
                    String nw = sm + s;
                    if (!nw.equals(py)) list.add(nw);
                }
            }
        } else {
            List<String> vs = changeVowel(py);
            return vs;
        }
        return list;
    }

    static private List<String> changeVowel(String s) {
        List<String> list = new ArrayList<>();
        list.add(s);
        if (s.endsWith("iang") || s.endsWith("ian")) return list;
        int len = s.length();
        for (Map.Entry<String, String> en : confusingMap.entrySet()) {
            String k = en.getKey(), v = en.getValue();
            if (s.endsWith(k)) {
                list.add(s.substring(0, len - k.length()) + v);
                break;
            } else if (s.endsWith(v)) {
                list.add(s.substring(0, len - v.length()) + k);
                break;
            }
        }
        return list;
    }

    public static void main(String[] args) {
        System.out.println(expand(new String[]{"niu","nai"}));
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值