我们使用编年史地图在大量不同的存储中支持堆外持久性,但在最简单的用例中遇到了一些问题。
首先,以下是我为简化创建而编写的帮助程序:
import java.io.File
import java.util.concurrent.atomic.AtomicLong
import com.madhukaraphatak.sizeof.SizeEstimator
import net.openhft.chronicle.map.{ChronicleMap, ChronicleMapBuilder}
import scala.reflect.ClassTag
object ChronicleHelper {
def estimateSizes[Key, Value](data: Iterator[(Key, Value)], keyEstimator: AnyRef => Long = defaultEstimator, valueEstimator: AnyRef => Long = defaultEstimator): (Long, Long, Long) = {
println("Estimating sizes...")
val entries = new AtomicLong(1)
val keySum = new AtomicLong(1)
val valueSum = new AtomicLong(1)
var i = 0
val GroupSize = 5000
data.grouped(GroupSize).foreach { chunk =>
chunk.par.foreach { case (key, value) =>
entries.incrementAndGet()
keySum.addAndGet(keyEstimator(key.asInstanceOf[AnyRef]))
valueSum.addAndGet(valueEstimator(value.asInstanceOf[AnyRef]))
}
i += 1
println("Progress:" + i * GroupSize)
}
(entries.get(), keySum.get() / entries.get(), valueSum.get() / entries.get())
}
def defaultEstimator(v: AnyRef): Long = SizeEstimator.estimate(v)
def createMap[Key: ClassTag, Value: ClassTag](data: => Iterator[(Key, Value)], file: File): ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]
val (entries, averageKeySize, averageValueSize) = estimateSizes(data)
val builder = ChronicleMapBuilder.of(keyClass, valueClass)
.entries(entries)
.averageKeySize(averageKeySize)
.averageValueSize(averageValueSize)
.asInstanceOf[ChronicleMapBuilder[Key, Value]]
val cmap = builder.createPersistedTo(file)
val GroupSize = 5000
println("Inserting data...")
var i = 0
data.grouped(GroupSize).foreach { chunk =>
chunk.par.foreach { case (key, value) =>
cmap.put(key, value)
}
i += 1
println("Progress:" + i * GroupSize)
}
cmap
}
def empty[Key: ClassTag, Value: ClassTag]: ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]
ChronicleMapBuilder.of(keyClass, valueClass).create()
}
def loadMap[Key: ClassTag, Value: ClassTag](file: File): ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]
ChronicleMapBuilder.of(keyClass, valueClass).createPersistedTo(file)
}
}
它使用https://github.com/phatak-dev/java-sizeof进行对象大小估计。以下是我们想要支持的用法类型:
object TestChronicle {
def main(args: Array[String]) {
def dataIterator: Iterator[(String, Int)] = (1 to 5000).toIterator.zipWithIndex.map(x => x.copy(_1 = x._1.toString))
ChronicleHelper.createMap[String, Int](dataIterator, new File("/tmp/test.map"))
}
}
但它抛出了一个例外:
[错误]线程“main”java中出现异常。ClassCastException:键必须是int,但它是java类。lang.Integer[错误]在网络上。openhft。编年史搞砸impl。瓦尼拉。net上的checkKey(vanillahorgehash.java:661)[错误]。openhft。编年史地图瓦尼利亚地图。queryContext(VanillaChronicleMap.java:281)[错误]位于net。openhft。编年史地图瓦尼利亚地图。将(VanillaChronicleMap.java:390)[错误]放在。。。
我可以看到它可能与Scala的Int的原子性有关,而不是Java的整数,但是我如何绕过它呢?
Scala 2.11.7
纪事地图3.8.0
>
Iterator[(String,Int)]
(而不是Iterator[(Int,String)]
),因为键类型是String
,值类型是Int
,而错误消息是关于键的类型(Int/Integer)键必须是%type%
,则表示您在第一个编年史映射生成器中配置了该类型。of(keyType,valueType)
语句。因此,在您的例子中,这意味着您配置了int.class
(class
对象,表示Java中的原语int
类型),这是不允许的,并且提供了Java。lang.Integer
实例映射的方法(可能您提供了原语int
s,但由于装箱,它们变成了Integer
),这是允许的。您应该确保您提供的是java。lang.Integer。类
(或其他一些Scala类)到编年史MapBuilder。of(keyType,valueType)
调用
我不知道这个项目的规模估计是多少:https://github.com/phatak-dev/java-sizeof,但在任何情况下,都应该以字节为单位指定对象将采用序列化形式的大小。序列化表单本身取决于默认序列化程序(为历史记录映射中的特定类型选择)(并且可能在历史记录映射版本之间更改)或为特定历史记录映射生成器配置的自定义序列化程序。因此,使用有关键/值“大小”的任何信息来配置历史记录映射(除了历史记录映射本身之外)是脆弱的。可以使用以下步骤更可靠地估计尺寸:
public static <V> double averageValueSize(Class<V> valueClass, Iterable<V> values) {
try (ChronicleMap<Integer, V> testMap = ChronicleMap.of(Integer.class, valueClass)
// doesn't matter, anyway not a single value will be written to a map
.averageValueSize(1)
.entries(1)
.create()) {
LongSummaryStatistics statistics = new LongSummaryStatistics();
for (V value : values) {
try (MapSegmentContext<Integer, V, ?> c = testMap.segmentContext(0)) {
statistics.accept(c.wrapValueAsData(value).size());
}
}
return statistics.getAverage();
}
}
您可以在此测试中找到它:https://github.com/OpenHFT/Chronicle-Map/blob/7aedfba7a814578a023f7975ef15ba88b4d435db/src/test/java/eg/AverageValueSizeTest.java
这个程序很粗糙,但现在没有更好的选择。
另一项建议:
如果您的键或值是某种原语(整数、长整数、双精度,但已装箱),或者任何其他类型的键或值总是大小相同,则不应使用averageKey/averageValue/averageKeySize/averageValueSize
方法,最好使用constantKeySizeBySample/constantValueSizeBySample
方法。专门针对java。lang.Integer
、Long
和Double
即使不需要,编年史地图已经知道这些类型的大小是不断变化的
在描述中说: 编年史映射提供内存访问速度,并支持超低垃圾收集。编年史地图可以支持最苛刻的应用程序。
思想?
我们有一个在50台服务器上使用相同数据集(键值对)的系统。对该数据集的更新数量约为每小时1000次,并且必须在这50台服务器上复制。我们有一个主系统接收这些更新,并负责将这些更新传播到其他服务器。目前,我们每小时以文件的形式将整个数据集(而不是增量更新)同步到所有服务器。然后将这些数据加载到不可变的Koloboke映射中。每个服务器每秒处理大约25000个请求,每个请求对这个映射进行30次查找。在
一个简单的问题:我看到chronicle Map3x正在将一些功能转移到引擎产品中。然而,引擎本身依赖于MAP2X。我有点困惑,我怎么能把它们一起用呢?我想我错过了什么,但不确定到底是什么。
我有以下映射定义,其中map.containsKey()显然不起作用: 我使用的是编年史地图2.4.17,在我的项目中迁移到版本3太难了。
问题内容: 所以今天有人问我这个问题。 该程序将输出什么?它返回true。我回答由于我对自动装箱(和自动装箱)的了解,它将始终打印为false。我的印象是,为Integer分配a = 3将创建一个新的Integer(3),以便an ==将对引用进行评估,而不是原始值。 谁能解释一下? 问题答案: 缓存在-128到127之间的框值。装箱使用方法,该方法使用缓存。超出范围的值不会被缓存,并且始终创建为