В настоящее время я внедряю общую модель для визуализации визуальных данных в 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?
Благодарю!
С миллионом записей всегда будут какие-то столкновения (если ваш массив намного длиннее 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;
}
HashMap
слишком медленный, база данных будет еще намного медленнее. Это не имеет никакого смысла.