java使用ac算法實現關鍵詞高亮


需求背景

標記出一句話中所有關鍵詞
inpu:我想買蘋果手機,請問哪里可以買蘋果手機
keyword:"蘋果", "蘋果手機", "哪里"
result:我想買[[蘋果手機]],請問[[哪里]]可以買[[蘋果手機]]
10w條耗時:41ms

難點:需要考慮單詞重疊問題(overlap),例如“蘋果手機”同時包含兩個關鍵詞,只標記一次。

思路

  1. 通過ac自動機遍歷得到所有關鍵詞;
  2. 新建一個byte[],長度等於原句子,根據ac算法結果將關鍵字位置設為1;
  3. 將原句子轉為char[],遍歷char[]和byte[],如果byte[]前后位置不一致,則插入替換符;
    3.1 如果前一個為1,后一個為0,則插入“]]”;
    3.2 如果前一個為0,后一個為1,則插入“[[”;
  4. 判斷末尾是否插入替換符;

代碼

pom文件引入hanlp,使用其中ac算法

<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.7.8</version>
</dependency>
package com.bincoder.StringUtils;

import com.hankcs.hanlp.collection.AhoCorasick.AhoCorasickDoubleArrayTrie;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;

public class KeywordMatch {

    /**
     * 構建ac自動機
     */
    public static AhoCorasickDoubleArrayTrie<String> buildAcdt(List<String> keywords){
        AhoCorasickDoubleArrayTrie<String> acdt = new AhoCorasickDoubleArrayTrie<>();
        TreeMap<String, String> map = new TreeMap<>();
        for(String keyword : keywords){
            map.put(keyword, keyword);
        }
        acdt.build(map);
        return acdt;
    }

    public static String highLight(String originText, AhoCorasickDoubleArrayTrie<String> acdt){
        List<int[]> hitLocationList = new ArrayList<>();
        // ac算法匹配關鍵詞
        acdt.parseText(originText, (begin, end, value)->{
           int[] indexPair = new int[2];
           indexPair[0] = begin;
           indexPair[1] = end-1;
           hitLocationList.add(indexPair);
        });
        // 構建bitmap
        byte[] posStatus = new byte[originText.length()];
        for(int[] item : hitLocationList){
            posStatus[item[0]] = 1;
            for(int i=item[0]; i<=item[1]; i++){
                posStatus[i] = 1;
            }
        }
        // 字符串拼接
        int lastStatus = 0;
        char[] charArray = originText.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0; i<posStatus.length; i++){
            if(posStatus[i] == lastStatus){
                stringBuilder.append(charArray[i]);
            }else if(0 == lastStatus){
                stringBuilder.append("[[").append(charArray[i]);
                lastStatus = 1;
            }else if(1 == lastStatus){
                stringBuilder.append("]]").append(charArray[i]);
                lastStatus = 0;
            }
            if(i == posStatus.length-1 && 1 == lastStatus){
                stringBuilder.append("]]");
            }
        }

        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String text = "我想買蘋果手機,請問哪里可以買蘋果手機";
        List<String> keywords = Arrays.asList("蘋果", "蘋果手機", "哪里");

        AhoCorasickDoubleArrayTrie<String> acdt = KeywordMatch.buildAcdt(keywords);
        String result = KeywordMatch.highLight(text, acdt);
        System.out.println("inpu:" + text);
        System.out.println("result:" + result);

        long start = System.currentTimeMillis();
        for(int i=0; i<100000; i++){
            result = KeywordMatch.highLight(text, acdt);
        }
        long end = System.currentTimeMillis();
        long total = end - start;
        System.out.println("耗時:" + total + "ms");

    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM