分享

Spark 高级分析:第八章第6节 GeoJSON简介

feilong 2018-9-28 10:36:49 发表于 连载型 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 2 6926
问题导读

1.GeoJson
是什么?如何使用?
2.
Spray是什么
?如何使用?
3.常用的
Scala Collections API方法有哪些


关注最新经典文章,欢迎关注公众号



上一篇:第八章第3-5节 利用Scala处理时间空间数据
http://www.aboutyun.com/forum.php?mod=viewthread&tid=25276

我们将使用纽约州边界的数据以GojJSON格式编写。GeoJSON中的核心对象称为一个特征,它由一个几何实例和一组称为属性的键值对组成。几何形状是如点、线、多边形等图形。一组特征称为特征集。让我们把GeoJSON数据拖到纽约自治区地图上,看看它的结构。


在客户端机器上的taxidata目录中,下载数据并将文件重命名为更短的内容:
[mw_shl_code=scala,true]wget https://nycdatastables.s3.amazonaws.com/2013-08-19T18:15:35.172Z/
nyc-borough-boundaries-polygon.geojson
mv nyc-borough-boundaries-polygon.geojson nyc-boroughs.geojson
[/mw_shl_code]打开文件并查看特性记录,注意属性和几何对象——在本例中,是表示行政区边界的多边形,以及包含行政区名称和其他相关信息的属性。Esri Geometry API将帮助我们解析每个特性内部的几何JSON,但不会帮助我们解析id或属性字段,这些字段可以是任意JSON对象。为了解析这些对象,我们需要使用Scala JSON库,其中有很多我们可以选择的。

Spray是一个开源的工具包,用于与Scala一起构建Web服务,它提供了一个符合任务的JSON库。Spray-json允许我们通过调用隐式toJson方法将任何Scala对象转换成相应的JSValue,并且还允许我们通过调用parseJson来将包含JSON的任何字符串转换成解析的中间形式,然后通过调用convertTo[T]将其转换为Scala类型T。Spray带有普通的Scala原语类型以及元组和集合类型的内置转换实现,并且它还具有一个格式化库,允许我们声明将RigGeometry类自定义类型转换为JSON的规则。

首先,我们需要创建一个用于表示GeoJSON特征的case类。根据规范,一个特性是一个JSON对象,它需要具有一个与GeoJSON几何类型相对应的名为“geometry”的字段,和一个名为“properties”的字段,该字段是具有任意数量的任意类型的键值对的JSON对象。一个特性也可以有一个可选的“id”字段,它可以是任何JSON标识符。我们的Feature case类将为每个JSON字段定义相应的Scala字段,并将添加一些方便的方法来从属性映射中查找值:
[mw_shl_code=scala,true]import spray.json.JsValue
case class Feature(
val id: Option[JsValue],
val properties: Map[String, JsValue],
val geometry: RichGeometry) {
def apply(property: String) = properties(property)
def get(property: String) = properties.get(property)
}
[/mw_shl_code]
我们使用RichGeometry类的实例来表示Feature中的geometry字段,我们将在Esri Geometry API的GeoJSON几何解析函数的帮助下创建该实例。我们还需要一个对应于GeJSON特征收集的case类。为了使特征集类更易于使用,我们将通过执行适当的apply和length方法来扩展IndexedSeq[Fask]特性,因此,我们可以直接在FeatureCollection实例本身上调用标准的Scala Collections API方法,比如map、filter和sortBy.,而不必访问它所包装的底层Array[Feature]值:
[mw_shl_code=scala,true]case class FeatureCollection(features: Array[Feature])
extends IndexedSeq[Feature] {
def apply(index: Int) = features(index)
def length = features.length
}
[/mw_shl_code]
在定义了GeoJSON数据的case类之后,我们需要定义告诉Spray如何在我们的域对象(RichGeometry, Feature, and FeatureCollection)之间转换的格式,以及相应的JsValue实例。为此,我们需要创建Scala 单例对象,扩展RootJsonFormat[T]特性,定义abstract read(jsv: JsValue): T and write(t: T): JsValue方法。对于RichGeometry类,我们可以将大部分解析和格式化逻辑委托给Esri geometry API,特别是GeometryEngine类上的geometryToGeoJson和geometryFromGeoJson方法,但是对于我们的案例类,我们需要自己编写格式化代码。下面是特性案例类的格式化代码,包括一些特殊的逻辑来处理可选id字段:
[mw_shl_code=scala,true]implicit object FeatureJsonFormat extends
RootJsonFormat[Feature] {
def write(f: Feature) = {
val buf = scala.collection.mutable.ArrayBuffer(
"type" -> JsString("Feature"),
"properties" -> JsObject(f.properties),
"geometry" -> f.geometry.toJson)
f.id.foreach(v => { buf += "id" -> v})
JsObject(buf.toMap)
}
def read(value: JsValue) = {
val jso = value.asJsObject
val id = jso.fields.get("id")
val properties = jso.fields("properties").asJsObject.fields
val geometry = jso.fields("geometry").convertTo[RichGeometry]
Feature(id, properties, geometry)
}
}
[/mw_shl_code]
FeatureJsonFormat对象使用implicit关键字,以便在JSValue实例调用convertTo[Feature]方法时,Spray库可以查找它。您可以在GitHub上的GeoJSON库的源代码中看到RootJsonFormat实现的其余部分。



已有(2)人评论

跳转到指定楼层
jiangzi 发表于 2018-9-28 12:34:57
Spark 高级分析:第八章第6节 GeoJSON~~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条