Быстрый доступ к значению из строкового ключа

1

В настоящее время я внедряю общую модель для визуализации визуальных данных в ColdFusion 9.

Я не заинтересован в поддержке нескольких мер, и модель предоставляет функцию numeric valueAt(string colKey, string rowKey) которая может быть вызвана представлением, чтобы получить полученное агрегирование меры на основе размеров столбцов и строк.

Например, с приведенными ниже данными, если для измерения была AVG(Age) и размерность Rank, тогда model.valueOf('3', '') вернет 2.33.

Wine  Age Rank
WineA 3    3
WineB 4    2
WineC 2    3
WineD 2    3

Теперь структура данных, которая, естественно, приходила мне в голову, заключалась в использовании java.util.HashMap для хранения вычисленных данных, используя комбинацию значений столбцов и строк, преобразованных в строку как ключи. Это означает, что в зависимости от набора данных у меня может быть очень много ключей, которые будут начинаться с того же префикса.

Я намеренно создал большой набор данных (1 миллион записей) с несколькими строками, имеющими один и тот же префикс, и проверил процент коллизий в String.hashCode() я получал бы с использованием стандартного java- String.hashCode() и MurmurHash3.

Вот как я создаю образец набора данных:

<cfset maxItemsCount = 1000000>
<cfset tokens = ['test', 'one', 'two', 'tree', 'four', 'five']>
<cfset tokensLen = arrayLen(tokens)>
<cfset items = []>
<cfset loopCount = 1>

<cfloop condition="arrayLen(items) lt maxItemsCount">
    <cfset item = ''>

    <cfloop from="1" to="#tokensLen#" index="i">
        <cfset item = listAppend(item, tokens[i] & loopCount, '_')>
        <cfset arrayAppend(items, item)>
    </cfloop>

    <cfset ++loopCount>
</cfloop>

С массивом, инициализированным 2 * entries count, я получил 27% столкновений с String.hashCode() и 22% для Murmur. Это заняло около 2580 миллисекунд с помощью java.util.HashMap только для хранения и извлечения ключей один раз.

Я ищу идеи о том, как повысить производительность, будь то использование разных структур данных (возможно, вложенных хеш-карт?) Или найти способ уменьшить количество коллизий без ущерба для подписи API?

Благодарю!

  • 0
    Разве это не цель использования базы данных? Почему вы пытаетесь изобрести велосипед?
  • 0
    @ControlAltDel Если HashMap слишком медленный, база данных будет еще намного медленнее. Это не имеет никакого смысла.
Показать ещё 1 комментарий
Теги:
performance
coldfusion
hashmap

1 ответ

1

С миллионом записей всегда будут какие-то столкновения (если ваш массив намного длиннее 1е12 записей: D). Я думаю, что MurmurHash делает здесь идеальную работу, но вы можете попробовать MD5 для сравнения (что, как правило, гарантирует идеальную работу).

Теперь структура данных, которая, естественно, приходила мне в голову, заключалась в использовании java.util.HashMap для хранения вычисленных данных, используя комбинацию значений столбцов и строк, преобразованных в строку как ключи. Это означает, что в зависимости от набора данных у меня может быть очень много ключей, которые будут начинаться с того же префикса.

Вы конкатенируете Струны и таким образом производят довольно мусор. Возможно, лучше создать

@Value static class Key {
    private final String row;
    private final String column;
}

как ключ для вашего HashMap, где @Value представляет собой аннотацию Lombok, генерирующую все скучные вещи, такие как equals, hashCode и конструктор.

Вы легко можете сделать это без Lombok и даже немного лучше:

static class Key {
    Key(String row, String column) {
         // Do NOT use 31 as a multiplier as it increases the number of collisions!
         // Try Murmur, too.
         hashCode = row.hashCode() + 113 * column.hashCode();
         this.row = row;
         this.column = column;
    }

    public int hashCode() {
        return hashCode;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key that = (Key) o;
        // Check hashCode first.
        if (this.hashCode != that.hashCode) return false;
        if (!this.row.equals(that.row)) return false;
        if (!this.column.equals(that.column)) return false;
        return true;
    }

    private final int hashCode;
    private final String row;
    private final String column;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню