我想检查句子是否包含映射到类别的单词列表中的单词。所以我有一个KeyValue.java类,包含单词,类别名称和方法filterCategory来检查它是否包含单词。现在我有10,000个关键字为文本映射了不同的类别。但问题是它是缓慢的方式。你能否提出一些其他方法来加快分类。谢谢你的帮助。
public class KeyValue {
private String key;
private String value;
public KeyValue(String key, String value) {
this.key = key;
this.value= value;
}
public KeyValue() {
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
Classification.java
class Classification
{
private static List<KeyValue> keyMap = new ArrayList<KeyValue>();
static{
getWordMap();
}
public static List<KeyValue> getWordMap()
{
if(keyMap.size()==0)
{
keyMap.add(new KeyValue("sports","football"));
keyMap.add(new KeyValue("sports","basketball"));
keyMap.add(new KeyValue("sports","olympics"));
keyMap.add(new KeyValue("sports","cricket"));
keyMap.add(new KeyValue("sports","t20"));
}
}
public static KeyValue filterCategory(String filteredText)
{
KeyValue kv = null;
for(KeyValue tkv:keyMap)
{
String value = tkv.getValue();
String lc = filteredText.toLowerCase();
lc = FormatUtil.replaceEnglishSymbolsWithSpace(lc);//remove symbols with space and then normalizes it
String lastWord="";
if(lc.contains(" "))
{
lastWord = lc.substring(lc.lastIndexOf(" ")+1);
if(lc.startsWith(value+" ") || lc.contains(" "+value+" ") || value.equals(lastWord))
{
kv = new KeyValue(tkv.getKey(), tkv.getValue());
break;
}
}
else if(lc.contains(value))
{
kv = new KeyValue(tkv.getKey(), tkv.getValue());
break;
}
}
if(kv==null)
{
return new KeyValue("general","0");
}
else
{
kv.setValue("100");
return kv;
}
}
}
答案 0 :(得分:0)
我不明白为什么你不使用Java的util.Map来解决这个问题,但我建议你迭代使用:
lc = FormatUtil.replaceEnglishSymbolsWithSpace(lc);
String result= Arrays.stream(lc.split(" ")).filter(s -> s.equals(value)).findFirst().orElse("");
if(result.length()>0) {
kv = tkv;
}
答案 1 :(得分:0)
您的实施是合理的,但对KeyValue对象使用Exhaustive or Brute-Force Search算法,而不是使用Hashing和HashMap or Hashtable对象等更快的匹配算法。
<强>假设强>
问题
你的逻辑,正如所写的那样,将执行强力搜索,尝试为你的句子中的每个单词进行10,000次匹配。如果句子中的每个单词都不存在于KeyValue对象中,则使用上面给出的短语将创建(10,000)x(9)= 90,000 最大尝试次数。
此逻辑会创建Big-O的最差情况或Θ(n)性能点击,其中 n 表示列表中的字数。这称为线性搜索。对此方法的一种惰性改进是使用排序列表,为您提供更好的Θ(log(n)) 对数搜索时间。
修复
使用散列算法,而不是执行强力搜索,一次对整个单词执行查找;或者,如果您想通过字符移位执行模式匹配,请查看Rabin—Karp Hash Algorithm。在简单匹配整个单词的情况下,您的算法会将您的句子单词分解为标记(就像您现在所使用的那样),然后对您的值和相关类别的散列图使用散列函数查找。
您的新逻辑将具有Θ(1)的Big-O性能。这种恒定时间匹配将大大提高您的应用速度。
<强>伪代码强>
// Adapting your KeyValue into a simple <Value, Key> map e.g. <"football", "sports">
//HashMap<String, String> map = new HashMap<String, String>();
// Adapting your KeyValue into a <Value, Set<Key>> map for multiple
// category keys e.g. <"football", <"sports","sunday","games">>
HashMap<String, Set<String>> map = new HashMap<String, Set<String>>();
// build the hashmap with your values and categories
Set<String> categories = new HashSet<String>();
categories.add("sports");
categories.add("sunday");
categories.add("games");
map.put("football", categories);
...
// sanitize your input
String lc = filteredText.toLowerCase();
lc = FormatUtil.replaceEnglishSymbolsWithSpace(lc);
// tokenize your sentence
String[] tokens = lc.split("\\s");
...
// search tokens against your hashmap
for (String token : tokens) {
// search the token against the hashmap
if (map.containsKey(token)){
Set<String> cats = map.get(token);
...
} else {
...
}
}
答案 2 :(得分:0)
根据建议,我发布了最快的代码,我可以提出。
基于KeyValue的List已被修改为简单的HashMap
private static HashMap<String,String> map = new HashMap<String,String>();
感谢您的建议。它现在可以扩展到投入生产。
public static KeyValue filterCategory(String filteredText)
{
KeyValue kv = null;
filteredText = filteredText.toLowerCase();
filteredText = FormatUtil.replaceEnglishSymbolsWithSpace(filteredText);
StringTokenizer tokenizer = new StringTokenizer(filteredText);
while(tokenizer.hasMoreTokens()) {
String temp = tokenizer.nextToken();
if(map.containsKey(temp))
{
kv = new KeyValue(map.get(temp),"100");
break;
}
}
if(kv==null)
{
kv= new KeyValue("general","0");
}
return kv;
}