Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Scala中使用盒装/原子值和编年史地图_Java_Scala_Chronicle_Chronicle Map - Fatal编程技术网

Java 在Scala中使用盒装/原子值和编年史地图

Java 在Scala中使用盒装/原子值和编年史地图,java,scala,chronicle,chronicle-map,Java,Scala,Chronicle,Chronicle Map,我们使用编年史地图在大量不同的存储中支持堆外持久性,但在最简单的用例中遇到了一些问题 首先,以下是我为简化创建而编写的帮助程序: import java.io.File import java.util.concurrent.atomic.AtomicLong import com.madhukaraphatak.sizeof.SizeEstimator import net.openhft.chronicle.map.{ChronicleMap, ChronicleMapBuilder}

我们使用编年史地图在大量不同的存储中支持堆外持久性,但在最简单的用例中遇到了一些问题

首先,以下是我为简化创建而编写的帮助程序:

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)
  }
}
它用于对象大小估计。以下是我们希望支持的使用方式:

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.lang.ClassCastException中出现异常:Key 必须是int,但在处是类java.lang.Integer[error] net.openhft.chronicle.hash.impl.VanillaChronicleHash.checkKey(VanillaChronicleHash.java:661) [错误]在 net.openhft.chronicle.map.VanillaChronicleMap.queryContext(VanillaChronicleMap.java:281) [错误]在 net.openhft.chronicle.map.VanillaChronicleMap.put(VanillaChronicleMap.java:390) [错误]在

我可以看出,这可能与Scala的Int的原子性有关,而不是与Java的Integer有关,但我如何绕过它呢

Scala 2.11.7

编年史地图3.8.0
  • 似乎怀疑在您的测试中是
    Iterator[(String,Int)]
    (而不是
    Iterator[(Int,String)]
    ),因为键类型是
    String
    ,值类型是
    Int
    ,而错误消息是关于键的类型(Int/Integer)
  • 如果错误消息说
    键必须是%type%
    ,则表示您在(keyType,valueType)语句的第一个
    编年史映射生成器中配置了该类型。因此,在您的例子中,这意味着您配置了
    int.class
    class
    对象,表示Java中的原语
    int
    类型),这是不允许的,并且为map的方法提供了
    Java.lang.Integer
    实例(可能您提供了原语
    int
    s,但由于装箱,它们变成了
    Integer
    ),这是允许的。您应该确保您提供了
    java.lang.Integer.class
    (或其他一些Scala类)给
    ChronicleMapBuilder.of(keyType,valueType)
    调用
  • 我不知道这个项目给出了什么大小估计:,但在任何情况下,您都应该以字节为单位指定对象将采用序列化形式的大小。序列化形式本身取决于默认的序列化程序,这些序列化程序是为编年史映射中的特定类型选择的(并且可能在编年史映射版本之间更改),或为特定的
    编年史映射生成器
    配置的自定义序列化程序。因此,使用有关键/值“大小”的任何信息来配置编年史映射(而不是编年史映射本身)是脆弱的。您可以使用以下过程更可靠地估计大小:

    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();
        }
    }
    
    public静态双平均值大小(Class-valueClass,Iterable-values){
    try(chronicmap testMap=chronicmap.of(Integer.class,valueClass)
    //不管怎样,没有一个值会写入映射
    .平均值大小(1)
    .参赛作品(1)
    .create()){
    LongSummaryStatistics=新的LongSummaryStatistics();
    对于(V值:值){
    try(MapSegmentContext c=testMap.segmentContext(0)){
    accept(c.wrapValueAsData(value.size());
    }
    }
    返回统计信息。getAverage();
    }
    }
    
    您可以在此测试中找到它:

    这个程序很粗糙,但现在没有更好的选择

  • 另一项建议:

    • 如果您的键或值属于基本类型(整数、长整数、双精度,但已装箱),或任何其他大小相同的类型,您不应该使用
      averageKey/averageValue/averageKeySize/averageValueSize
      方法,最好使用
      constantKeySizeBySample/constantValueSizeBySample
      方法。特别是对于
      java.lang.Integer
      Long
      Double
      方法,即使不需要这样做d、 编年史地图已经知道这些类型的大小是不断变化的