データローダ
注
このセクションは、高レベルの API v2 には適用されません。
ロケーション ライブラリは 、 TileLoader インターフェイスを使用して必要なタイルをロードします。このインターフェイスによって、ライブラリは HERE タイリングスキームを使用するバージョン化されたレイヤーをモデル化します。
TileLoader
インスタンスを取得するに は、カタログインターフェイスからレイヤー名を選択します。このインターフェイスでは、レイヤー名を使用してTileLoader
を作成できます。
たとえば 、 Optimized Map for Location Library のマッピングレイヤーからタイルの生データを取得するには、次のコマンドを使用します。
import com.here.platform.location.dataloader.core.{Catalog, TileLoader}
import com.here.platform.location.dataloader.standalone.StandaloneCatalogFactory
val factory = new StandaloneCatalogFactory
try {
val optimizedMap: Catalog = factory.create(optimizedMapHRN, optimizedMapVersion)
val tileLoader: TileLoader[Array[Byte]] = optimizedMap.create("mapping")
val bytes: Option[Array[Byte]] = tileLoader.get(tileId)
println(s"The tile size is ${bytes.get.length} bytes")
} finally {
factory.terminate()
}
import com.here.platform.location.dataloader.core.Catalog;
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.standalone.StandaloneCatalogFactory;
import scala.Option;
final StandaloneCatalogFactory factory = new StandaloneCatalogFactory();
try {
final Catalog optimizedMap = factory.create(optimizedMapHRN, optimizedMapVersion);
final TileLoader<byte[]> tileLoader = optimizedMap.create("mapping");
final Option<byte[]> bytes = tileLoader.get(tileId);
System.out.println("The tile size is " + bytes.get().length + " bytes");
} finally {
factory.terminate();
}
以下の点に注意してください。
データローダーがアクセスするレイヤーに存在するすべてのタイル ID を含むイテレータを取得することもできます。 たとえば 、 Optimized Map for Location Library のジオメトリレイヤーにデータが含まれているタイルの数をカウントするには、次のようにします。
import com.here.platform.location.dataloader.core.{Catalog, TileLoader}
import com.here.platform.location.dataloader.standalone.StandaloneCatalogFactory
val factory = new StandaloneCatalogFactory
try {
val optimizedMap: Catalog = factory.create(optimizedMapHRN, optimizedMapVersion)
val tileLoader: TileLoader[Array[Byte]] = optimizedMap.create("geometry")
val tileIds: Iterator[TileId] = tileLoader.partitionIds
println(s"The ${tileLoader.layerName} layer contains ${tileIds.length} tiles")
} finally {
factory.terminate()
}
import com.here.platform.location.dataloader.core.Catalog;
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.standalone.StandaloneCatalogFactory;
import com.here.platform.location.inmemory.geospatial.TileId;
import scala.collection.Iterator;
final StandaloneCatalogFactory factory = new StandaloneCatalogFactory();
try {
final Catalog optimizedMap = factory.create(optimizedMapHRN, optimizedMapVersion);
final TileLoader<byte[]> tileLoader = optimizedMap.create("geometry");
final Iterator<TileId> tileIds = tileLoader.partitionIds();
System.out.println(
"The " + tileLoader.layerName() + " layer contains " + tileIds.size() + " tiles");
} finally {
factory.terminate();
}
TileLoader をキャッシュしています
コストを削減し、パフォーマンスを向上させるには、タイルのダウンロードを繰り返し行わないでください。 この問題を解決するために、ロケーション ライブラリに は、 LRUCachingTileLoader という名前のクラスが用意TileLoader
されています。このクラスは、次に示すように、設定可能なタイル数を、最近使用したことのない方法で保持できるように特化されたものです。
import com.here.platform.location.dataloader.core.TileLoader
import com.here.platform.location.dataloader.core.caching._
val tileLoader: TileLoader[Array[Byte]] = optimizedMap.create("mapping")
val numberOfTilesToRetain: Long = 8
val cachingTileLoader: CachingTileLoader[Array[Byte]] =
new LRUCachingTileLoader(tileLoader, numberOfTilesToRetain)
val bytes: Option[Array[Byte]] = cachingTileLoader.get(tileId)
val cachedBytes: Option[Array[Byte]] = cachingTileLoader.get(tileId)
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.core.caching.CachingTileLoader;
import com.here.platform.location.dataloader.core.caching.LRUCachingTileLoader;
import scala.Option;
final TileLoader<byte[]> tileLoader = optimizedMap.create("mapping");
final long numberOfTilesToRetain = 8;
final CachingTileLoader<byte[]> cachingTileLoader =
new LRUCachingTileLoader<>(tileLoader, numberOfTilesToRetain);
final Option<byte[]> bytes = cachingTileLoader.get(tileId);
final Option<byte[]> cachedBytes = cachingTileLoader.get(tileId);
スニペットで使用されている CachingTileLoader は、キャッシュも提供するTileLoader
です。
上記のスニペットの生データを使用できるようにする には、 Protobuf スキーマ the mapping
layer を使用してデータを解釈する必要があります。つまり、データをMappingPartition
インスタンスに変換します。 これを実現 するために、ロケーション ライブラリには TransformingTileLoader クラスが用意されています。このクラスは、別のTileLoader
によって返されたタイルに変換関数を適用します。
このクラスを使用すると、への変換を MappingPartition
次のように実装できます。
import com.here.platform.location.dataloader.core._
import com.here.platform.pb.location.optimizedmap.mapping.v2.mapping.MappingPartition
val tileLoader: TileLoader[Array[Byte]] = optimizedMap.create("mapping")
def transformingFunction(bytes: Array[Byte]): MappingPartition =
MappingPartition.parseFrom(bytes)
val transformingTileLoader: TileLoader[MappingPartition] =
new TransformingTileLoader(tileLoader, transformingFunction)
val mappingPartition: Option[MappingPartition] = transformingTileLoader.get(tileId)
mappingPartition.foreach(_.mapping.take(3).zipWithIndex.foreach {
case (hmcReference, vertexIndex) => println(s"$vertexIndex -> $hmcReference")
})
import com.google.protobuf.InvalidProtocolBufferException;
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.core.javadsl.TransformingTileLoader;
import com.here.platform.pb.location.optimizedmap.mapping.v2.Mapping.MappingPartition;
import scala.Option;
final TileLoader<byte[]> tileLoader = optimizedMap.create("mapping");
final TileLoader<MappingPartition> transformingTileLoader =
new TransformingTileLoader<>(
tileLoader,
data -> {
try {
return MappingPartition.parseFrom(data);
} catch (final InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
});
final Option<MappingPartition> maybeMappingPartition = transformingTileLoader.get(tileId);
if (maybeMappingPartition.isDefined()) {
final MappingPartition mappingPartition = maybeMappingPartition.get();
for (int vertexIndex = 0;
vertexIndex < Math.min(3, mappingPartition.getMappingCount());
vertexIndex++) {
System.out.println("vertexIndex: " + vertexIndex);
System.out.println(mappingPartition.getMapping(vertexIndex));
}
}
CacheManager
CacheManagerは 'High-Level API で幅広く使用されており ' 次の操作を行う方法を提供します
CacheManager
を作成する最も簡単 な方法は、ファクトリメソッドCacheManager.withLruCache()
を使用することです。このメソッドは、 InMemoryLruCachePolicy を使用して内部で LRUCachingTileLoader インスタンスを作成します。 このメソッドには、複数のオーバーロードがあります。これにより、すべてのエントリの最大数を設定できます CacheLevel
。次に例を示します。
import com.here.platform.location.dataloader.core.caching.CacheManager
val maxByteArrayEntryCount = 20L
val maxInMemoryEntryCount = 10L
val maxOnTheFlyEntryCount = 30L
val cacheManager = CacheManager.withLruCache(maxByteArrayEntryCount,
maxInMemoryEntryCount,
maxOnTheFlyEntryCount)
import com.here.platform.location.dataloader.core.caching.CacheManager;
final long maxByteArrayEntryCount = 20;
final long maxInMemoryEntryCount = 10;
final long maxOnTheFlyEntryCount = 30;
final CacheManager cacheManager =
CacheManager.withLruCache(
maxByteArrayEntryCount, maxInMemoryEntryCount, maxOnTheFlyEntryCount);
CacheKey
各 TileLoader
キーは CacheKey を使用して取得できます。 CacheKey は、カタログ、レイヤー名、および CacheLevel を識別する HERE リソースネーム とバージョンで構成されています。
CacheLevel
は 、TileLoader
リターンされるデータの種類に応じてTileLoader
を分類 します。このデータは、生のバイト、デコードされたデータ、またはオンザフライでコンパイルされたデータのいずれかになります。
import com.here.platform.location.dataloader.core.TileLoader
import com.here.platform.location.dataloader.core.caching.{CacheKey, CacheLevel}
val tileLoader: TileLoader[Array[Byte]] = optimizedMap.create("mapping")
val cacheKey = CacheKey(optimizedMap, tileLoader.layerName, CacheLevel.ByteArray)
println(cacheKey)
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.core.caching.CacheKey;
import com.here.platform.location.dataloader.core.caching.javadsl.CacheLevels;
final TileLoader<byte[]> tileLoader = optimizedMap.create("mapping");
final CacheKey cacheKey =
CacheKey.apply(optimizedMap, tileLoader.layerName(), CacheLevels.BYTE_ARRAY);
System.out.println(cacheKey);
オンザフライキャッシュレベル
オンザフライでコンパイルされた属性のタイルローダーを保持する場合は、オンザフライキャッシュレベルを使用 PropertyMaps.rangeBasedAttributes
します。この属性は、およびそのバリアント( roadAttribute 、 navigationAttribute 、 advancedNavigationAttribute )から取得されたものです。
次の例は、最適化されたマップカタログから派生したキーを持つオンザフライのタイルローダを作成する方法を示し ています。レイヤ名は、選択したcompiledLayerId
レイヤ名と同じで、キャッシュレベルはOnTheFly
に設定されています。
import com.here.platform.location.compilation.heremapcontent.AttributeAccessors
import com.here.platform.location.core.graph.RangeBasedProperty
import com.here.platform.location.dataloader.core.caching.{CacheKey, CacheLevel, CacheManager}
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps
import com.here.schema.rib.v2.road_attributes.FunctionalClassAttribute
import com.here.schema.rib.v2.road_attributes.FunctionalClassAttribute.FunctionalClass
import com.here.schema.rib.v2.road_attributes_partition.RoadAttributesPartition
val cacheManager = CacheManager.withLruCache()
val functionalClassAccessor =
AttributeAccessors
.forHereMapContentSegmentAnchor[RoadAttributesPartition,
FunctionalClassAttribute,
FunctionalClass](
_.functionalClass,
_.functionalClass
)
val compiledLayerId = "on-the-fly-compiled-function-class"
val functionalClassPropertyMap =
PropertyMaps.roadAttribute(optimizedMap,
compiledLayerId,
optimizedMap.resolveDependency(hereMapContentHRN),
cacheManager,
functionalClassAccessor)
val functionalClass: Seq[RangeBasedProperty[FunctionalClass]] =
functionalClassPropertyMap(vertex)
println(s"Functional classes for $vertex are (${functionalClass.map(_.value).mkString(",")})")
val onTheFlyCacheKeys =
cacheManager.loaders.stats.keys.filter(_.cacheLevel == CacheLevel.OnTheFly)
val cacheKey = CacheKey(optimizedMap, compiledLayerId, CacheLevel.OnTheFly)
assert(cacheKey == onTheFlyCacheKeys.head)
import com.here.platform.location.compilation.heremapcontent.javadsl.AttributeAccessor;
import com.here.platform.location.compilation.heremapcontent.javadsl.AttributeAccessors;
import com.here.platform.location.core.graph.javadsl.RangeBasedProperty;
import com.here.platform.location.core.graph.javadsl.RangeBasedPropertyMap;
import com.here.platform.location.dataloader.core.caching.CacheKey;
import com.here.platform.location.dataloader.core.caching.CacheManager;
import com.here.platform.location.dataloader.core.caching.javadsl.CacheLevels;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
import com.here.schema.rib.v2.road_attributes.FunctionalClassAttribute;
import com.here.schema.rib.v2.road_attributes_partition.RoadAttributesPartition;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static scala.collection.JavaConverters.mapAsJavaMapConverter;
final CacheManager cacheManager = CacheManager.withLruCache();
final AttributeAccessor<RoadAttributesPartition, FunctionalClassAttribute.FunctionalClass>
functionalClassAccessor =
AttributeAccessors.forHereMapContentSegmentAnchor(
RoadAttributesPartition::functionalClass,
FunctionalClassAttribute::functionalClass);
final String compiledLayerId = "on-the-fly-compiled-function-class";
final RangeBasedPropertyMap<Vertex, FunctionalClassAttribute.FunctionalClass>
functionalClassPropertyMap =
PropertyMaps.roadAttribute(
optimizedMap,
compiledLayerId,
optimizedMap.resolveDependency(hereMapContentHRN),
cacheManager,
functionalClassAccessor);
final List<RangeBasedProperty<FunctionalClassAttribute.FunctionalClass>> functionalClass =
functionalClassPropertyMap.get(vertex);
System.out.println(
String.format(
"Functional classes for %s are (%s)",
vertex,
functionalClass.stream()
.map(fc -> fc.value().toString())
.collect(Collectors.joining(","))));
final Stream<CacheKey> onTheFlyCacheKeys =
mapAsJavaMapConverter(cacheManager.loaders().stats()).asJava().keySet().stream()
.filter(k -> k.cacheLevel().equals(CacheLevels.ON_THE_FLY));
final CacheKey cacheKey = CacheKey.apply(optimizedMap, compiledLayerId, CacheLevels.ON_THE_FLY);
assertEquals(cacheKey, onTheFlyCacheKeys.findFirst().get());
定数 hereMapContentHRN
は 、カタログ HRNS およびバージョンのセクションで定義されています。
注
同じ HERE Map Content レイヤーから取得した複数のオンザフライでコンパイルされた属性にアクセスする場合は、 ByteArray キャッシュレベルのサイズとして 0 より大きい値を設定することをお勧めします。
これにより、 HERE Map Content パーティションは、コンパイル後に再ダウンロードされるのではなく、複数のオンザフライ属性のコンパイルに再利用されます。
CachingStats
特定のTileLoader
ののキャッシュ使用量に関する統計情報を表示する場合 は、CachingTileLoader.stats
メソッドを使用して取得できます。 キャッシュ使用量のグローバルな概要については、次の方法でも確認できます。
import com.here.platform.location.core.graph.PropertyMap
import com.here.platform.location.dataloader.core.caching._
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.geospatial.HereMapContentReference
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps
val cacheManager = CacheManager.withLruCache()
val vertexToHmc: PropertyMap[Vertex, HereMapContentReference] =
PropertyMaps.vertexToHereMapContentReference(optimizedMap, cacheManager)
val hmc: HereMapContentReference = vertexToHmc(vertex)
val cacheMissesForMappingLayer: Map[CacheLevel, Long] =
cacheManager.loaders.stats.collect {
case (CacheKey(_, _, "mapping", level), stats) => level -> stats.missCount
}
assert(cacheMissesForMappingLayer(CacheLevel.ByteArray) == 1)
assert(cacheMissesForMappingLayer(CacheLevel.InMemory) == 1)
import com.here.platform.location.core.graph.javadsl.PropertyMap;
import com.here.platform.location.dataloader.core.caching.CacheLevel;
import com.here.platform.location.dataloader.core.caching.CacheManager;
import com.here.platform.location.dataloader.core.caching.javadsl.CacheLevels;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.geospatial.HereMapContentReference;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
import java.util.Map;
import java.util.stream.Collectors;
import static scala.collection.JavaConverters.mapAsJavaMapConverter;
final CacheManager cacheManager = CacheManager.withLruCache();
final PropertyMap<Vertex, HereMapContentReference> vertexToHmc =
PropertyMaps.vertexToHereMapContentReference(optimizedMap, cacheManager);
final HereMapContentReference hmc = vertexToHmc.get(vertex);
final Map<CacheLevel, Long> cacheMissesForMappingLayer =
mapAsJavaMapConverter(cacheManager.loaders().stats()).asJava().entrySet().stream()
.filter(e -> e.getKey().layerName().equals("mapping"))
.collect(Collectors.toMap(e -> e.getKey().cacheLevel(), e -> e.getValue().missCount()));
assertEquals(1, (long) cacheMissesForMappingLayer.get(CacheLevels.BYTE_ARRAY));
assertEquals(1, (long) cacheMissesForMappingLayer.get(CacheLevels.IN_MEMORY));
この例では 、 PropertyMaps を使用 して、マッピングレイヤーの高レベルビューを作成します。
CachingPolicy
CacheManager.withLruCache
の上でより柔軟性が必要な場合 は、自分でCachingPolicy
作成してください。
LRUCachingTileLoader
特定のレイヤーの特定のキャッシュサイズを持つをそのとともに使用する場合は CacheLevel
、次のようにします。
import com.here.platform.location.dataloader.core.TileLoader
import com.here.platform.location.dataloader.core.caching._
val cacheManager = CacheManager.withCachingPolicy(new CachingPolicy {
override def createCachingTileLoader[T](cacheLevel: CacheLevel,
inner: TileLoader[T]): CachingTileLoader[T] =
(inner.layerName, cacheLevel) match {
case ("mapping", CacheLevel.InMemory) =>
new LRUCachingTileLoader[T](inner, size = 10)
case ("mapping", CacheLevel.ByteArray) =>
new LRUCachingTileLoader[T](inner, size = 100)
case _ => new LRUCachingTileLoader[T](inner, size = 5)
}
override def createCachingDataLoader[P, T](cacheLevel: CacheLevel,
inner: DataLoader[P, T]): CachingDataLoader[P, T] =
new LRUCachingDataLoader(inner, 5)
})
import com.here.platform.location.dataloader.core.DataLoader;
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.core.caching.*;
import com.here.platform.location.dataloader.core.caching.javadsl.CacheLevels;
CacheManager.withCachingPolicy(
new CachingPolicy() {
private static final long serialVersionUID = 1L;
@Override
public <T> CachingTileLoader<T> createCachingTileLoader(
final CacheLevel cacheLevel, final TileLoader<T> inner) {
if (inner.layerName().equals("mapping")) {
if (cacheLevel.equals(CacheLevels.IN_MEMORY))
return new LRUCachingTileLoader<>(inner, 10);
else if (cacheLevel.equals(CacheLevels.BYTE_ARRAY))
return new LRUCachingTileLoader<>(inner, 100);
}
return new LRUCachingTileLoader<>(inner, 5);
}
@Override
public <P, T> CachingDataLoader<P, T> createCachingDataLoader(
final CacheLevel cacheLevel, final DataLoader<P, T> inner) {
return new LRUCachingDataLoader<>(inner, 5);
}
});
LRUCachingTileLoader
とは異なるキャッシュ戦略が必要な場合 は、完全にカスタマイズされたCachingTileLoader
を記述してください。
生データ () をCacheLevel.ByteArray
特殊な方法で管理するには、次のコマンドを使用します。
import com.here.platform.location.dataloader.core.TileLoader
import com.here.platform.location.dataloader.core.caching._
class DiskCachingLoader[Id, T](inner: DataLoader[Id, T]) extends CachingDataLoader[Id, T] {
override def catalogHrn: HRN = inner.catalogHrn
override def catalogVersion: Long = inner.catalogVersion
override def layerName: String = inner.layerName
override def partitioning: LayerPartitioning = inner.partitioning
override def partitionIds: Iterator[Id] = inner.partitionIds
override def get(id: Id): Option[T] =
downloadIfAbsent(id).map(_.asInstanceOf[T])
override def getAll(ids: Iterable[Id]): Iterable[(Id, Option[T])] =
downloadIfAbsent(ids).map {
case (id, value) => (id, value.map(_.asInstanceOf[T]))
}
override def stats: CacheStats =
???
private def downloadIfAbsent(id: Id): Option[Array[Byte]] =
???
private def downloadIfAbsent(id: Iterable[Id]): Iterable[(Id, Option[Array[Byte]])] =
???
}
class DiskCachingPolicy extends CachingPolicy {
override def createCachingTileLoader[T](cacheLevel: CacheLevel,
inner: TileLoader[T]): CachingTileLoader[T] =
cacheLevel match {
case CacheLevel.ByteArray =>
CachingDataLoader.asTileLoader(new DiskCachingLoader[TileId, T](inner))
case _ => new LRUCachingTileLoader[T](inner, size = 5)
}
override def createCachingDataLoader[P, T](cacheLevel: CacheLevel,
inner: DataLoader[P, T]): CachingDataLoader[P, T] =
cacheLevel match {
case CacheLevel.ByteArray =>
new DiskCachingLoader(inner)
case _ => new LRUCachingDataLoader(inner, size = 5)
}
}
val cacheManager = CacheManager.withCachingPolicy(new DiskCachingPolicy)
import com.here.platform.location.dataloader.core.DataLoader;
import com.here.platform.location.dataloader.core.TileLoader;
import com.here.platform.location.dataloader.core.caching.*;
import com.here.platform.location.dataloader.core.caching.javadsl.CacheLevels;
import com.here.platform.location.dataloader.core.javadsl.AbstractTileLoaderDecorator;
import com.here.platform.location.inmemory.geospatial.TileId;
import scala.Option;
import scala.Tuple2;
import scala.collection.Iterable;
import scala.collection.JavaConverters;
import java.util.Collection;
import java.util.stream.Collectors;
class DiskCachingTileLoader<T> extends AbstractTileLoaderDecorator<T>
implements CachingTileLoader<T> {
public DiskCachingTileLoader(final TileLoader<T> inner) {
super(inner);
}
@Override
public CacheStats stats() {
throw new UnsupportedOperationException();
}
@Override
public Option<T> get(final long tileId) {
final Option<byte[]> result = downloadIfAbsent(tileId);
return parse(result);
}
@Override
public Iterable<Tuple2<TileId, Option<T>>> getAll(final Iterable<TileId> tileIds) {
final Collection<Tuple2<TileId, Option<byte[]>>> result =
downloadIfAbsent(JavaConverters.asJavaCollectionConverter(tileIds).asJavaCollection());
return JavaConverters.iterableAsScalaIterableConverter(
result.stream()
.map(tuple -> new Tuple2<>(tuple._1, parse(tuple._2)))
.collect(Collectors.toList()))
.asScala();
}
@SuppressWarnings("unchecked")
private Option<T> parse(final Option<byte[]> result) {
return (result.isDefined()) ? Option.apply((T) result.get()) : Option.empty();
}
private Option<byte[]> downloadIfAbsent(final long tileId) {
throw new UnsupportedOperationException();
}
private Collection<Tuple2<TileId, Option<byte[]>>> downloadIfAbsent(
final Collection<TileId> tileIds) {
throw new UnsupportedOperationException();
}
}
class DiskCachingPolicy extends CachingPolicy {
private static final long serialVersionUID = 1L;
@Override
public <T> CachingTileLoader<T> createCachingTileLoader(
final CacheLevel cacheLevel, final TileLoader<T> inner) {
return (cacheLevel.equals(CacheLevels.BYTE_ARRAY))
? new DiskCachingTileLoader<T>(inner)
: new LRUCachingTileLoader<T>(inner, 5);
}
@Override
public <P, T> CachingDataLoader<P, T> createCachingDataLoader(
final CacheLevel cacheLevel, final DataLoader<P, T> inner) {
return new LRUCachingDataLoader<>(inner, 5);
}
}
final CacheManager cacheManager = CacheManager.withCachingPolicy(new DiskCachingPolicy());