创建一个快速的android字典(字数)

时间:2014-08-20 00:04:32

标签: java android performance sqlite dictionary

我目前正在处理各种统计的申请。 一个任务是分析大量的句子用于他们的字数。

规格如下:

  • 句子从SQLiteDatabase读取(最多20k,平均约15个字)
  • 转换:用空格分割(得到句子的单词)
  • 转换:toLowerCase(最小化单词的变化)
  • 转换:替换[^ a-zA-Z](出于与上述相同的原因)
  • 得到第一个x(不确定,可能是10-15)最常见词语
  • 的字数+计数
  • 如果发送/接收消息,则保留标志

这是我目前的做法:

db.execSQL("create temp table if not exists WORDS (WORD varchar, SENT integer)");
Cursor c1 = db.rawQuery("select lower(MSG) as SENTENCE, SENT from MESSAGELIST",null);
    while (c.moveToNext()) {
        String[] words = c.getString(c.getColumnIndex("SENTENCE")).split(
                "\\s+");
        int from_me = c.getInt(c.getColumnIndex("SENT"));
        for (int i = 0; i < words.length; i++) {
            words[i] = words[i].replaceAll("[^a-zA-z]", "");
            if (!words[i].equals("")) {
                db.execSQL("insert into WORDS values ('" + words[i] + "', "
                        + from_me + ")");
            }
        }
    }
    Cursor c2 = db.rawQuery(
            "select WORD, COUNT(*) as CNT from WORDS where SENT=0 group by WORD order by CNT desc limit 10",
            null);
    Cursor c3 = db.rawQuery(
            "select WORD, COUNT(*) as CNT from WORDS where SENT=1 group by WORD order by CNT desc limit 10",
            null);

正如我已经假设这段代码很慢。我猜字符串操作需要花费很多时间。

从查询中提取并重新进入数据库也感觉不对。但是,我知道regexp_split_to_array中有regexp_split_to_tablePostgreSQL,这样可以保留数据库以进行查询。我还没有找到在SQLite

中执行此操作的解决方案

我花了很多时间试图找出不同的解决方案,但现在我有点陷入困境。有没有(相对)快速的方法来执行所需的任务?我也愿意让wordcount尽可能合理。

包含一些建议实施的当前版本:

改进:

  • 准备好的声明:快29%
  • 预编译正则表达式:快〜21%
  • 注释部分表示我对计数的实现,但这种方法提高了运行时间(有和没有索引)
  • 通过交易批量插入:快9%
  • CharMatcher替换:快8%
  • HashMultiset计数:快2%

    c = db.rawQuery("select lower(DATA) as SENTENCE, SENT from MESSAGELIST", null);
    
    CharMatcher pat_rep = CharMatcher.inRange('A', 'Z')
            .or(CharMatcher.inRange('a', 'z')).precomputed();
    Pattern pat_split = Pattern.compile("\\s");
    HashMultiset<String> sent = HashMultiset.create();
    HashMultiset<String> rcvd = HashMultiset.create();
    
    while (c.moveToNext()) {
        String[] words = pat_split.split(c.getString(c.getColumnIndex("SENTENCE")));
        int from_me = c.getInt(c.getColumnIndex("SENT"));
    
        for (int i = 0; i < words.length; i++) {
            words[i] = pat_rep.retainFrom(words[i]);
            if (!words[i].equals("")) {
                if (from_me == 1) {
                    sent.add(words[i]);
                } else {
                    rcvd.add(words[i]);
                }
            }
        }
    }
    db.execSQL("create temp table if not exists WORDS (WORD varchar, SENT integer, CNT integer)");
    SQLiteStatement ins = db.compileStatement("insert into WORDS values (?, ?, ?)");
    db.beginTransaction();
    
    Iterator<String> i = sent.iterator();
    while (i.hasNext()) {
        String in = i.next();
        ins.bindString(1, in);
        ins.bindLong(2, 1);
        ins.bindLong(3, sent.count(in));
        ins.executeInsert();
        ins.clearBindings();
    }
    i = rcvd.iterator();
    while (i.hasNext()) {
        String in = i.next();
        ins.bindString(1, in);
        ins.bindLong(2, 0);
        ins.bindLong(3, rcvd.count(in));
        ins.executeInsert();
        ins.clearBindings();
    }
    db.setTransactionSuccessful();
    db.endTransaction();
    c = db.rawQuery(
            "select WORD, CNT from WORDS where SENT=0 group by WORD order by CNT desc limit 10",
            null);
    Cursor c2 = db.rawQuery(
            "select WORD, CNT from WORDS where SENT=1 group by WORD order by CNT desc limit 10",
            null);
    

1 个答案:

答案 0 :(得分:1)

db.execSQL("insert into WORDS values ('" + words[i] + "', "
                    + from_me + ")");

数据库访问太多。为每个单词命中数据库都不顺利。由于重复了很多单词,你可以在Multiset中计算它们,并在它们的计数,内存紧张或你完成时存储它们。

为每次出现创建一个单独的行也没有意义。添加一个列count(最好将其称为&#34; count&#34;是关键字)。

使用准备好的陈述。通过每次创建一个查询字符串,您可以强制DB一次又一次地解析它。并且还为GC工作。

words[i] = words[i].replaceAll("[^a-zA-z]", "");

使用Pattern.compileCharMatcher。在没有特殊字符的常见情况下,后者不会产生垃圾。

private final CharMatcher alpha = CharMatcher.inRange('A', 'Z')
        .or(CharMatcher.inRange('a', 'z')).precomputed();

alpha.retainFrom(words[i]);

这应该有很多帮助,特别是DB的东西。尝试一下,如果还不够,请再来一次。