第一章
at org.apache.hadoop.ipc.RemoteException.instantiateException(RemoteException.j前期准备
在安装GeoMesa-Hbase之前,要保证服务器上已经正确安装JDK、Hadoop、Hbase等组件,具体版本要求如下:
1)
Java JDK 1.8
2)
Apache Maven 3.5.2 或更新版本
3)
Github客户端
4)
Hadoop 2.7.x(建议)
5)
Hbase 1.3.x 或者1.4.x
下载方式有两种,可以直接从Github上面下载已经编译好的二进制文件,也可以下载后利用maven进行编译
1. 下载后直接解压
从Github下载已经编译好的二进制文件,解压至目标目录($VERSION是你想要下载的版本,我测试成功的是2.1.0)
1. # download and unpackage the most recent distribution:
2. wget "https://github.com/locationtech/geomesa/releases/download/geomesa_2.11-$VERSION/geomesa-hbase-dist_2.11-$VERSION-bin.tar.gz"
3. tar -xvf geomesa-hbase-dist_2.11-$VERSION-bin.tar.gz
4. cd geomesa-hbase-dist_2.11-$VERSION
5. ls
6. bin/ conf/ dist/ docs/ examples/ lib/ LICENSE.txt logs/
2. 下载源码后编译
由于考虑到日后需要基于GeoMesa进行二次开发,也可以采用编译GeoMesa源代码的方式。
下载geomesa源码(VERSION是你想要的版本)
1. git clone https://github.com/locationtech/geomesa.git
进入geomesa的根目录然后进行编译
1. mvn clean install -DskipTests=true
编译成功后,GeoMesa HBase的完整安装包位于geomesa-hbase\geomesa-hbase-dist\target目录下解压
1. sudo tar -xvf geomesa-hbase_2.11-$VERSION-SNAPSHOT-bin.tar.gz /home/software
修改权限
1. sudo chown -R wjk:hadoop /usr/local/geomesa-hbase_2.11-$VERSION-SNAPSHOT
拷贝到其他机器上
1. sudo scp -r /usr/local/geomesa-hbase_2.11-$VERSION-SNAPSHOT root@192.168.201.92:/usr/local/
为了程序的正常运行和操作方便,建议配置Hadoop、Hbase、GeoMesa-Hbase的环境变量。下述三种方式都可以。
1. 在 /etc/profile文件中配置(主要为了操作方便)
将下列环境变量添加在profile文件当中。
1. export HADOOP_HOME=/path/to/hadoop
2. export HBASE_HOME=/path/to/hbase
3. export GEOMESA_HBASE_HOME=/opt/geomesa
4. export PATH="${PATH}:${GEOMESA_HBASE_HOME}/bin"
应用配置文件。
由于许可的原因,需要在geomesa根目录下手动执行以下两个命令,安装两个插件。
1. bin/install-jai.sh
2. bin/install-jline.sh
2. 在geomesa本身的环境配置文件中设置
GeoMesa 推荐在geomesa-hbase_2.11-$VERSION/conf/geomesa-env.sh文件中设置以上环境变量 。
1. export HADOOP_HOME=/path/to/hadoop
2. export HBASE_HOME=/path/to/hbase
3. export GEOMESA_HBASE_HOME=/opt/geomesa
4. export PATH="${PATH}:${GEOMESA_HBASE_HOME}/bin"
由于许可的原因,需要在geomesa根目录下手动执行以下两个命令,安装两个插件。
3. bin/install-jai.sh
4. bin/install-jline.sh
3. 在外部环境中配置环境变量
修改.bashrc
添加环境变量
1. export HADOOP_HOME=/path/to/hadoop
2. export HBASE_HOME=/path/to/hbase
3. export GEOMESA_HBASE_HOME=/opt/geomesa
4. export PATH="${PATH}:${GEOMESA_HBASE_HOME}/bin"
由于许可的原因,需要在geomesa根目录下手动执行以下两个命令,安装两个插件。
1. bin/install-jai.sh
2. bin/install-jline.sh
GeoMesa for HBase需要使用本地过滤器来加速查询,因此需要将GeoMesa的runtime JAR包,拷贝到HBase的库目录下。
官网给的默认设置是拷贝至HDFS中,其中${hbase.dynamic.jars.dir}是${hbase.rootdir}/lib
1. hadoop fs -put ${GEOMESA_HBASE_HOME}/dist/hbase/geomesa-hbase-distributed-runtime-$VERSION.jar ${hbase.dynamic.jars.dir}/
注意:如果是分布式环境,需要将其复制到每一个节点。
GeoMesa使用HBase自定义过滤器来改进CQL查询的处理。要使用自定义筛选器,必须将分布式运行时jar部署到HBase,并将其部署到由调用的HBase配置变量指定的目录中
将/dist/hbase/geomesa-hbase-distributed-runtime_2.11-2.1.0-SNAPSHOT.jar拷贝到${HBase_HOME}/lib目录下。
1. cp /home/software/geomesa-hbase_2.11-$VERSION-SNAPSHOT/dist/hbase/geomesa-hbase-distributed-runtime_2.11-$VERSION-SNAPSHOT.jar /home/software/hbase-1.3.3/lib/
注意:此处还需要把geomesa-hbase-distributed-runtime_2.11-2.1.0-SNAPSHOT.jar 拷贝到/tmp/hbase-${usr}/hbase/lib/下(这个目录可能不存在,我是通过自己创建目录解决的),并且每个机器都要这样做,运行时会找这个jar包的。这个地方在其它资料里都没提到,但很重要。
1. cp /home/software/geomesa-hbase_2.11-$VERSION-SNAPSHOT/dist/hbase/geomesa-hbase-distributed-runtime_2.11-$VERSION-SNAPSHOT.jar /tmp/hbase-root/hbase/lib/
GeoMesa利用服务器端处理来加速某些查询。为了利用这些功能,GeoMesa协处理器必须在所有GeoMesa表上注册或在站点范围内注册,并且geomesa-hbase-distributed-runtime代码必须在类路径或HDFS URL上可用,具体取决于所使用的注册方法。
为了使HBase在运行时能够访问到geomesa-hbase-distributed-runtime的jar包。官网给出了几种方法实现这一目标,最方便的是在HBase的配置文件hbase-site.xml添加如下内容:
1. <property>
2. <name>hbase.coprocessor.user.region.classes</name>
3. <value>org.locationtech.geomesa.hbase.coprocessor.GeoMesaCoprocessor</value>
4. </property>
注意:如果是分布式环境,需要在每一个节点都添加相同的内容。
官方文档提供的其他几种方法参考https://www.geomesa.org/documentation/user/hbase/install.html
在完成以上设置后,GeoMesa的主要部分就安装完成了。可以使用 bin/geomesa-hbase命令调用GeoMesa的命令行工具,执行一系列的功能。
这里要额外设置的是使用如下命令,将HBase配置文件hbase-site.xml打包进geomesa-hbase-datastore_2.11-$VERSION.jar中:
1. zip -r lib/geomesa-hbase-datastore_2.11-$VERSION.jar hbase-site.xml
这一步的目的是确保在MapReduce任务中,GeoMesa能够顺利访问到该文件。
在这个过程当中,可能出现不能百分百执行完的情况,这是因为geomesa-hbase本身不能涵盖所有功能,因此不必担心。
重新启动zookeeper、hadoop、hbase,然后查看geomesa-hbase的版本
得到版本信息,标志着geomesa-hbase已经安装成功
1. GeoMesa tools version: 2.1.0-SNAPSHOT
2. Commit ID: 72ace4b8499fa0958a85a7b424f1fde47c446049
3. Branch: master
4. Build date: 2018-09-05T23:21:35-0400
下载:
1. git clone https://github.com/geomesa/geomesa-tutorials.git
2. cd geomesa-tutorials
查看pom.xml文件,修改hadoop和hbase版本,要和你已安装的版本保持一致。修改后,使用maven进行构建:
1. mvn clean install -pl geomesa-tutorials-hbase/geomesa-tutorials-hbase-quickstart -am
建议在构建之前,将mvn的源多设置几个,因为国内的源(例如阿里云)虽然传输比较快,但是资源并不完整,很多jar包都不完整。
构建完成后,在命令行执行以下命令
1. java -cp geomesa-tutorials-hbase/geomesa-tutorials-hbase-quickstart/target/geomesa-tutorials-hbase-quickstart-$VERSION.jar \
2. org.geomesa.example.hbase.HBaseQuickStart \
3. --hbase.zookeepers <zookeepers> \
4. --hbase.catalog <table>
--hbase.zookeepers填zookeeper的位置,在单机模式下,这个值为localhost。对于已经将hbase-site.xml设为GeoMesa能够访问的情况(按照第一部分完成安装),则这一项可以不填。不过依然建议将这一项写全。
--hbase.catalog 填HBase表的名称,用于存放测试数据。所填的表要么为空,要么不存在,否则会出错。
注意:在填写zookeepers时,一定保证本机和其他机器的网络通畅,如果在本地测试,服务器集群内的机器只有内网地址没有外网地址的话,可能会出现找不到zookeeper node的问题。
1.
输出结果
正常情况下,可以得到如下结果:
1. Loading datastore
2.
3. Creating schema: GLOBALEVENTID:String,Actor1Name:String,Actor1CountryCode:String,Actor2Name:String,Actor2CountryCode:String,EventCode:String,NumMentions:Integer,NumSources:Integer,NumArticles:Integer,ActionGeo_Type:Integer,ActionGeo_FullName:String,ActionGeo_CountryCode:String,dtg:Date,geom:Point:srid=4326
4.
5. Generating test data
6.
7. Writing test data
8. Wrote 2356 features
9.
10. Running test queries
11. Running query BBOX(geom, -120.0,30.0,-75.0,55.0) AND dtg DURING 2017-12-31T00:00:00+00:00/2018-01-02T00:00:00+00:00
12. 01 719027236=719027236|UNITED STATES|USA|INDUSTRY||012|1|1|1|3|Central Valley, California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.682 34.0186)
13. 02 719027005=719027005|UNITED STATES|USA|||172|2|2|2|3|Long Beach, California, United States|US|2018-01-01T00:00:00.000Z|POINT (-118.189 33.767)
14. 03 719026204=719026204|JUDGE||||0214|6|1|6|3|Los Angeles, California, United States|US|2018-01-01T00:00:00.000Z|POINT (-118.244 34.0522)
15. 04 719025745=719025745|KING||||051|4|2|4|2|California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
16. 05 719026858=719026858|UNITED STATES|USA|||010|20|2|20|2|California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
17. 06 719026964=719026964|UNITED STATES|USA|||081|2|2|2|2|California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
18. 07 719026965=719026965|CALIFORNIA|USA|||081|8|1|8|2|California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
19. 08 719025635=719025635|PARIS|FRA|||010|2|1|2|3|Las Vegas, Nevada, United States|US|2018-01-01T00:00:00.000Z|POINT (-115.137 36.175)
20. 09 719026918=719026918|UNITED STATES|USA|||042|20|5|20|3|Las Vegas, Nevada, United States|US|2018-01-01T00:00:00.000Z|POINT (-115.137 36.175)
21. 10 719027141=719027141|ALABAMA|USA|JUDGE||172|8|1|8|2|Nevada, United States|US|2018-01-01T00:00:00.000Z|POINT (-117.122 38.4199)
22.
23. Returned 669 total features
24.
25. Running query BBOX(geom, -120.0,30.0,-75.0,55.0) AND dtg DURING 2017-12-31T00:00:00+00:00/2018-01-02T00:00:00+00:00
26. Returning attributes [GLOBALEVENTID, dtg, geom]
27. 01 719027208=719027208|2018-01-01T00:00:00.000Z|POINT (-89.6812 32.7673)
28. 02 719026313=719026313|2018-01-01T00:00:00.000Z|POINT (-84.388 33.749)
29. 03 719026419=719026419|2018-01-01T00:00:00.000Z|POINT (-84.388 33.749)
30. 04 719026316=719026316|2018-01-01T00:00:00.000Z|POINT (-83.6487 32.9866)
31. 05 719027132=719027132|2018-01-01T00:00:00.000Z|POINT (-81.2793 33.4968)
32. 06 719026819=719026819|2018-01-01T00:00:00.000Z|POINT (-81.9296 33.7896)
33. 07 719026952=719026952|2018-01-01T00:00:00.000Z|POINT (-81.9296 33.7896)
34. 08 719026881=719026881|2018-01-01T00:00:00.000Z|POINT (-82.0193 34.146)
35. 09 719026909=719026909|2018-01-01T00:00:00.000Z|POINT (-82.0193 34.146)
36. 10 719026951=719026951|2018-01-01T00:00:00.000Z|POINT (-82.0193 34.146)
37.
38. Returned 669 total features
39.
40. Running query EventCode = '051'
41. 01 719024909=719024909|||MELBOURNE|AUS|051|10|1|10|4|Melbourne, Victoria, Australia|AS|2018-01-01T00:00:00.000Z|POINT (144.967 -37.8167)
42. 02 719025178=719025178|AUSTRALIA|AUS|COMMUNITY||051|20|2|20|4|Sydney, New South Wales, Australia|AS|2018-01-01T00:00:00.000Z|POINT (151.217 -33.8833)
43. 03 719025965=719025965|MIDWIFE||||051|10|1|10|4|Sydney, New South Wales, Australia|AS|2018-01-01T00:00:00.000Z|POINT (151.217 -33.8833)
44. 04 719025509=719025509|COMMUNITY||AUSTRALIA|AUS|051|2|1|2|1|Australia|AS|2018-01-01T00:00:00.000Z|POINT (135 -25)
45. 05 719025742=719025742|KING||||051|22|3|22|3|San Diego, California, United States|US|2018-01-01T00:00:00.000Z|POINT (-117.157 32.7153)
46. 06 719025745=719025745|KING||||051|4|2|4|2|California, United States|US|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
47. 07 719025743=719025743|AUTHORITIES||||051|60|12|60|3|Wichita, Kansas, United States|US|2018-01-01T00:00:00.000Z|POINT (-97.3375 37.6922)
48. 08 719027205=719027205|UNITED STATES|USA|SIOUX||051|4|1|4|3|Sioux City, Iowa, United States|US|2018-01-01T00:00:00.000Z|POINT (-96.4003 42.5)
49. 09 719025111=719025111|||UNITED STATES|USA|051|2|1|2|3|Pickens County, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-82.7165 34.9168)
50. 10 719026938=719026938|PITTSBURGH|USA|||051|5|1|5|3|York County, Pennsylvania, United States|US|2018-01-01T00:00:00.000Z|POINT (-77 40.1254)
51.
52. Returned 138 total features
53.
54. Running query EventCode = '051' AND dtg DURING 2017-12-31T00:00:00+00:00/2018-01-02T00:00:00+00:00
55. Returning attributes [GLOBALEVENTID, dtg, geom]
56. 01 719024909=719024909|2018-01-01T00:00:00.000Z|POINT (144.967 -37.8167)
57. 02 719025178=719025178|2018-01-01T00:00:00.000Z|POINT (151.217 -33.8833)
58. 03 719025965=719025965|2018-01-01T00:00:00.000Z|POINT (151.217 -33.8833)
59. 04 719025509=719025509|2018-01-01T00:00:00.000Z|POINT (135 -25)
60. 05 719025742=719025742|2018-01-01T00:00:00.000Z|POINT (-117.157 32.7153)
61. 06 719025745=719025745|2018-01-01T00:00:00.000Z|POINT (-119.746 36.17)
62. 07 719025743=719025743|2018-01-01T00:00:00.000Z|POINT (-97.3375 37.6922)
63. 08 719027205=719027205|2018-01-01T00:00:00.000Z|POINT (-96.4003 42.5)
64. 09 719025111=719025111|2018-01-01T00:00:00.000Z|POINT (-82.7165 34.9168)
65. 10 719026938=719026938|2018-01-01T00:00:00.000Z|POINT (-77 40.1254)
66.
67. Returned 138 total features
68.
69. Cleaning up test data
70. Done
如果出错,说明GeoMesa没有安装成功,或者是底层的HDFS、Hbase出了问题,要根据错误提示具体分析。
从输出结果看,这一实例程序完成了创建schema、写入features、空间查询、属性查询等操作。具体实现可以查看教程中的源代码文件。
2.
Hbase中的表结构
查看hbase当中的数据,相关的表共有5个
1. hbase(main):019:0> list
2.
3. TABLE
4. geomesa-hbase-test01
5. geomesa-hbase-test01_gdelt_2dquickstart_attr_v5
6. geomesa-hbase-test01_gdelt_2dquickstart_id
7. geomesa-hbase-test01_gdelt_2dquickstart_z2_v2
8. geomesa-hbase-test01_gdelt_2dquickstart_z3_v2
其中geomesa-hbase-test01表记录表的信息
geomesa-hbase-test01_gdelt_2dquickstart_attr_v5
表是属性索引表
geomesa-hbase-test01_gdelt_2dquickstart_id表是id索引表
geomesa-hbase-test01_gdelt_2dquickstart_z2_v2是空间索引表(经纬度)
geomesa-hbase-test01_gdelt_2dquickstart_z3_v2是时间空间索引表
1.
缺少协处理器
错误信息:
1. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/coprocessor/CoprocessorService
2. at java.lang.ClassLoader.defineClass1(Native Method)
3. at java.lang.ClassLoader.defineClass(Unknown Source)
4. at java.security.SecureClassLoader.defineClass(Unknown Source)
5. at java.net.URLClassLoader.defineClass(Unknown Source)
6. at java.net.URLClassLoader.access$100(Unknown Source)
7. at java.net.URLClassLoader$1.run(Unknown Source)
8. at java.net.URLClassLoader$1.run(Unknown Source)
9. at java.security.AccessController.doPrivileged(Native Method)
10. at java.net.URLClassLoader.findClass(Unknown Source)
11. at java.lang.ClassLoader.loadClass(Unknown Source)
12. at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
13. at java.lang.ClassLoader.loadClass(Unknown Source)
14. at org.locationtech.geomesa.hbase.coprocessor.package$.AllCoprocessors$lzycompute(package.scala:28)
15. at org.locationtech.geomesa.hbase.coprocessor.package$.AllCoprocessors(package.scala:27)
16. at org.locationtech.geomesa.hbase.index.HBaseFeatureIndex$class.configure(HBaseFeatureIndex.scala:95)
17. at org.locationtech.geomesa.hbase.index.HBaseZ2Index$.configure(HBaseZ2Index.scala:21)
18. at org.locationtech.geomesa.hbase.index.HBaseZ2Index$.configure(HBaseZ2Index.scala:21)
19. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore$$anonfun$onSchemaCreated$1.apply(GeoMesaDataStore.scala:161)
20. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore$$anonfun$onSchemaCreated$1.apply(GeoMesaDataStore.scala:161)
21. at scala.collection.immutable.List.foreach(List.scala:381)
22. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore.onSchemaCreated(GeoMesaDataStore.scala:161)
23. at org.locationtech.geomesa.index.geotools.MetadataBackedDataStore.createSchema(MetadataBackedDataStore.scala:150)
24. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore.createSchema(GeoMesaDataStore.scala:178)
25. at org.locationtech.geomesa.hbase.data.HBaseDataStore.createSchema(HBaseDataStore.scala:54)
26. at com.zgss.test.Test5.main(Test5.java:31)
27. Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.coprocessor.CoprocessorService
28. at java.net.URLClassLoader$1.run(Unknown Source)
29. at java.net.URLClassLoader$1.run(Unknown Source)
30. at java.security.AccessController.doPrivileged(Native Method)
31. at java.net.URLClassLoader.findClass(Unknown Source)
32. at java.lang.ClassLoader.loadClass(Unknown Source)
33. at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
34. at java.lang.ClassLoader.loadClass(Unknown Source)
35. ... 25 more
解决方法:
以上是因为缺少hbase的协处理器的相关包,加上下面的依赖,问题解决。
1. <dependency>
2. <groupId>com.aliyun.hbase</groupId>
3. <artifactId>alihbase-endpoint</artifactId>
4. <version>2.0.0</version>
5. </dependency>
2.
Jar包冲突
报错信息如下:NoSuchMethodErrot
1. Exception in thread "main" java.lang.NoSuchMethodError: org.geotools.factory.FactoryRegistry.getFactory(Ljava/lang/Class;Ljava/util/function/Predicate;Lorg/geotools/factory/Hints;Lorg/geotools/factory/Hints$Key;)Ljava/lang/Object;
2. at org.geotools.factory.CommonFactoryFinder.lookup(CommonFactoryFinder.java:329)
3. at org.geotools.factory.CommonFactoryFinder.getFilterFactory(CommonFactoryFinder.java:284)
4. at org.geotools.factory.CommonFactoryFinder.getFilterFactory2(CommonFactoryFinder.java:370)
5. at org.geotools.factory.CommonFactoryFinder.getFilterFactory2(CommonFactoryFinder.java:383)
6. at org.geotools.data.DataUtilities.<clinit>(DataUtilities.java:204)
7. at com.zgss.test.Test5.main(Test5.java:30)
解决方法:
Jar包冲突,把gt-data的jar包去掉就好了
3.
Geotools jar包冲突
报错信息:NoSuchElementException
1. Exception in thread "main" java.util.NoSuchElementException: key not found: class org.locationtech.jts.geom.Point
2. at scala.collection.MapLike$class.default(MapLike.scala:228)
3. at scala.collection.AbstractMap.default(Map.scala:59)
4. at scala.collection.MapLike$class.apply(MapLike.scala:141)
5. at scala.collection.AbstractMap.apply(Map.scala:59)
6. at org.locationtech.geomesa.utils.geotools.AttributeSpec$class.getClassSpec(SimpleFeatureSpec.scala:85)
7. at org.locationtech.geomesa.utils.geotools.AttributeSpec$GeomAttributeSpec.getClassSpec(SimpleFeatureSpec.scala:156)
8. at org.locationtech.geomesa.utils.geotools.AttributeSpec$class.toSpec(SimpleFeatureSpec.scala:59)
9. at org.locationtech.geomesa.utils.geotools.AttributeSpec$GeomAttributeSpec.toSpec(SimpleFeatureSpec.scala:160)
10. at org.locationtech.geomesa.utils.geotools.SimpleFeatureTypes$.encodeDescriptor(SimpleFeatureTypes.scala:166)
11. at org.locationtech.geomesa.utils.geotools.SimpleFeatureTypes$$anonfun$encodeType$1.apply(SimpleFeatureTypes.scala:162)
12. at org.locationtech.geomesa.utils.geotools.SimpleFeatureTypes$$anonfun$encodeType$1.apply(SimpleFeatureTypes.scala:162)
13. at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
14. at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
15. at scala.collection.Iterator$class.foreach(Iterator.scala:742)
16. at scala.collection.AbstractIterator.foreach(Iterator.scala:1194)
17. at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
18. at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
19. at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
20. at scala.collection.AbstractTraversable.map(Traversable.scala:104)
21. at org.locationtech.geomesa.utils.geotools.SimpleFeatureTypes$.encodeType(SimpleFeatureTypes.scala:162)
22. at org.locationtech.geomesa.index.geotools.MetadataBackedDataStore.writeMetadata(MetadataBackedDataStore.scala:391)
23. at org.locationtech.geomesa.index.geotools.MetadataBackedDataStore.createSchema(MetadataBackedDataStore.scala:141)
24. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore.createSchema(GeoMesaDataStore.scala:178)
25. at org.locationtech.geomesa.hbase.data.HBaseDataStore.createSchema(HBaseDataStore.scala:54)
26. at org.locationtech.geomesa.hbase.data.HBaseDataStore.createSchema(HBaseDataStore.scala:29)
27. at com.zgss.test.Test5.main(Test5.java:33)
解决方法:
把geotools的相关jar包全部删除,问题就解决了。可能是因为jar包冲突。
4.
找不到runtime包
报错信息:DoNotRetryIOException
6. org.apache.hadoop.hbase.DoNotRetryIOException: org.apache.hadoop.hbase.DoNotRetryIOException: Class org.locationtech.geomesa.hbase.coprocessor.GeoMesaCoprocessor cannot be loaded Set hbase.table.sanity.checks to false at conf or table descriptor if you want to bypass sanity checks
7. at org.apache.hadoop.hbase.master.HMaster.warnOrThrowExceptionForFailure(HMaster.java:1818)
8. at org.apache.hadoop.hbase.master.HMaster.sanityCheckTableDescriptor(HMaster.java:1679)
9. at org.apache.hadoop.hbase.master.HMaster.createTable(HMaster.java:1609)
10. at org.apache.hadoop.hbase.master.MasterRpcServices.createTable(MasterRpcServices.java:472)
11. at org.apache.hadoop.hbase.protobuf.generated.MasterProtos$MasterService$2.callBlockingMethod(MasterProtos.java:58714)
12. at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2191)
13. at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:112)
14. at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:183)
15. at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:163)
16. ava:106)
17. at org.apache.hadoop.ipc.RemoteException.unwrapRemoteException(RemoteException.java:95)
18. at org.apache.hadoop.hbase.client.RpcRetryingCaller.translateException(RpcRetryingCaller.java:226)
19. at org.apache.hadoop.hbase.client.RpcRetryingCaller.translateException(RpcRetryingCaller.java:244)
20. at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithRetries(RpcRetryingCaller.java:140)
21. at org.apache.hadoop.hbase.client.HBaseAdmin.executeCallable(HBaseAdmin.java:4117)
22. at org.apache.hadoop.hbase.client.HBaseAdmin.executeCallable(HBaseAdmin.java:4110)
23. at org.apache.hadoop.hbase.client.HBaseAdmin.createTableAsyncV2(HBaseAdmin.java:736)
24. at org.apache.hadoop.hbase.client.HBaseAdmin.createTable(HBaseAdmin.java:657)
25. at org.locationtech.geomesa.hbase.index.HBaseFeatureIndex$class.configure(HBaseFeatureIndex.scala:97)
26. at org.locationtech.geomesa.hbase.index.HBaseZ3Index$.configure(HBaseZ3Index.scala:21)
27. at org.locationtech.geomesa.hbase.index.HBaseZ3Index$.configure(HBaseZ3Index.scala:21)
28. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore$$anonfun$onSchemaCreated$1.apply(GeoMesaDataStore.scala:161)
29. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore$$anonfun$onSchemaCreated$1.apply(GeoMesaDataStore.scala:161)
30. at scala.collection.immutable.List.foreach(List.scala:381)
31. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore.onSchemaCreated(GeoMesaDataStore.scala:161)
32. at org.locationtech.geomesa.index.geotools.MetadataBackedDataStore.createSchema(MetadataBackedDataStore.scala:150)
33. at org.locationtech.geomesa.index.geotools.GeoMesaDataStore.createSchema(GeoMesaDataStore.scala:178)
34. at org.locationtech.geomesa.hbase.data.HBaseDataStore.createSchema(HBaseDataStore.scala:54)
35. at org.locationtech.geomesa.hbase.data.HBaseDataStore.createSchema(HBaseDataStore.scala:29)
36. at com.zgss.dmp.geomesa.utils.GeomesaUtils.createSchema(GeomesaUtils.java:51)
37. at com.zgss.dmp.geomesa.GeomesaTimedTask.PredictionTimedTask.writePredictionTimeTask(PredictionTimedTask.java:53)
38. at com.zgss.dmp.geomesa.GeomesaTimedTask.PredictionTimedTask.main(PredictionTimedTask.java:31)
解决办法:
找到geomesa-hbase-distributed-runtime包,按照前述的目录位置将该包拷贝过去。
1.
创建Option
由于之后的操作可能涉及到多个操作,因此利用Options类来对这些操作信息进行封装
1. public Options createOptions(Param[] parameters) {
2. Options options = new Options();
3. for (Param p: parameters) {
4. if (!p.isDeprecated()) {
5. Option opt = Option.builder(null)
6. .longOpt(p.getName())
7. .argName(p.getName())
8. .hasArg()
9. .desc(p.getDescription().toString())
10. .required(p.isRequired())
11. .build();
12. options.addOption(opt);
13. }
14. }
15. return options;
16. }
2.
解析参数
由于geomesa的信息并不是利用configure来进行封装的,而是利用args来进行传输和解析的,因此对此需要进行规定。在这里使用了默认的解析器(DefaultParser)
1. public CommandLine parseArgs(Class<?> caller, Options options, String[] args) throws ParseException {
2. try {
3. return new DefaultParser().parse(options, args);
4. } catch (ParseException e) {
5. System.err.println(e.getMessage());
6. HelpFormatter formatter = new HelpFormatter();
7. formatter.printHelp(caller.getName(), options);
8. throw e;
9. }
10. }
3.
获取DataStore的参数
在此方法中主要是为了利用上述的解析器和获取的操作参数,最终封装成为一个Map,key为操作名称,value为操作的值。而在此方法中,zookeepers为zk集群的地址信息,catalog为在hbase当中的目录名称(类似于RDBMS中的数据库的概念),但是为了使此方法更加灵活,这个参数没有写死,而是作为一个参数进行传入。
1. public Map<String, String> getDataStoreParams(String catalog) throws ParseException {
2. String[] args ={"--hbase.catalog", catalog, "--hbase.zookeepers", "localhost:2181"};
3. Options options = this.createOptions(new HBaseDataStoreFactory().getParametersInfo());
4. CommandLine command = this.parseArgs(getClass(), options, args);
5. Map<String, String> params = new HashMap<>();
6. // noinspection unchecked
7. for (Option opt: options.getOptions()) {
8. String value = command.getOptionValue(opt.getLongOpt());
9. if (value != null) {
10. params.put(opt.getArgName(), value);
11. }
12. }
13. return params;
14. }
4.
创建DataStore
1. public DataStore createHbaseDataStore(String catalog) throws IOException, ParseException {
2. Map<String, String> params = this.getDataStoreParams(catalog);
3. return DataStoreFinder.getDataStore(params);
4. }
SimpleFeatureType是Geotools当中表示数据类型的一个概念,但是geomesa当中的SimpleFeatureType和Geotools当中的有所不同,具体细节参见本文的附录二。
1. public SimpleFeatureType getSimpleFeatureType() {
2. if (sft == null) {
3. StringBuilder attributes = new StringBuilder();
4. attributes.append("taxiId:String,");
5. attributes.append("dtg:Date,");
6. attributes.append("*geom:Point:srid=4326,");
7. attributes.append("speed:string,");
8. attributes.append("isDriven:string");
9.
10. sft = SimpleFeatureTypes.createType(getTypeName(), attributes.toString());
11. sft.getUserData().put(SimpleFeatureTypes.DEFAULT_DATE_KEY, "dtg");
12. }
13. return sft;
14. }
其中第6行当中的“srid”是GIS当中的一个空间引用标识符。而此处的“srid=4326”表示这些数据对应的WGS 84空间引用系统。
第10行中的getTypeName返回值也是String类型,用户也可以直接属于一个type名称(String类型)
1. dataStore.createSchema(sft);
这一步主要是为了将sft传入特定dataStore中的createSchema方法当中,执行创建Schema的操作。
此时就要获取相关的数据进行插入。Geomesa的数据插入支持多种格式文件,例如csv、txt,此处以csv为例。
1. public List<SimpleFeature> getTestData() {
2. if (features == null) {
3. List<SimpleFeature> features = new ArrayList<>();
4.
5. URL input = getClass().getClassLoader().getResource("test.csv");
6. if (input == null) {
7. throw new RuntimeException("Couldn't load resource test.csv");
8. }
9.
10. // 设定日期的格式,此处需要用到正则表达式
11. DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
12.
13. // 使用geotools当中的SimpleFeatureType来生成我们需要的Feature
14. SimpleFeatureBuilder builder = new SimpleFeatureBuilder(getSimpleFeatureType());
15.
16. try (CSVParser parser = CSVParser.parse(input, StandardCharsets.UTF_8, CSVFormat.DEFAULT)) {
17. for (CSVRecord record : parser) {
18. // 对于每个字段和csv文件的对应关系进行设定
19. builder.set("taxiId", record.get(0));
20. builder.set("dtg", Date.from(LocalDateTime.parse(record.get(1), dateFormat).toInstant(ZoneOffset.UTC)));
21. double longitude = Double.parseDouble(record.get(3));
22. double latitude = Double.parseDouble(record.get(2));
23.
24. builder.set("geom", "POINT (" + longitude + " " + latitude + ")");
25. builder.set("speed", record.get(4));
26. builder.set("isDriven", record.get(5));
27.
28. // 向Geotools确认要用用户自行设定的id
29. builder.featureUserData(Hints.USE_PROVIDED_FID, Boolean.TRUE);
30.
31. // 设定一个id,此处是taxiID
32. features.add(builder.buildFeature(record.get(1)));
33. }
34. } catch (IOException e) {
35. throw new RuntimeException("Error reading t-drive data:", e);
36. }
37. this.features = Collections.unmodifiableList(features);
38. }
39. return features;
40. }
注意:GeoMesa的数据库结构有三层,catalog、type、feature,可以类比关系型数据库当中的数据库、表和行。此处返回的features就是很多行数据的集合。
注意:此处的数据插入是将全量的数据先存入内存当中,这样很容易造成内存溢出的问题,因此建议批量插入。
获取到数据之后就可以将这些数据写入到geomesa当中了。
1. public void writeFeatures(DataStore datastore, SimpleFeatureType sft, List<SimpleFeature> features) throws IOException {
2. if (features.size() > 0) {
3. System.out.println("Writing test data");
4. try (FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
5. datastore.getFeatureWriterAppend(sft.getTypeName(), Transaction.AUTO_COMMIT)) {
6. for (SimpleFeature feature : features) {
7. try {
8. SimpleFeature toWrite = writer.next();
9. toWrite.setAttributes(feature.getAttributes());
10. ((FeatureIdImpl) toWrite.getIdentifier()).setID(feature.getID());
11. toWrite.getUserData().put(Hints.USE_PROVIDED_FID, Boolean.TRUE);
12. toWrite.getUserData().putAll(feature.getUserData());
13. writer.write();
14. }catch (Exception e){
15. logger.debug("Invalid GDELT record: " + e.toString() + " " + feature.getAttributes());
16. }
17. }
18. }
19. }
20. }
1.
查询全部数据
1. @Override
2. public List<Query> getTestQueries() {
3. if (queries == null) {
4. List<Query> queries = new ArrayList<>();
5. queries.add(new Query(getTypeName(), Filter.INCLUDE));
6. this.queries = Collections.unmodifiableList(queries);
7. }
8. return queries;
9. }
2.
按照时空条件查询
在第6行和第7行出现了两个String类型的字符串,这是ECQL,一种针对地理信息的查询语句,其语法和通常的SQL略有不同,详情见附录1。
1. public List<Query> getTestQueries() {
2. if (queries == null) {
3. try {
4. List<Query> queries = new ArrayList<>();
5.
6. String during = "dtg DURING 2159-01-01T00:00:00.000Z/2169-01-01T00:00:00.000Z";
7. String bbox = "bbox(geom,128,48,133,53)";
8.
9. //时空查询
10. queries.add(new Query(getTypeName(), ECQL.toFilter(bbox+" AND "+during)));
11. //空间查询
12. queries.add(new Query(getTypeName(), ECQL.toFilter(bbox)));
13. //时间查询
14. queries.add(new Query(getTypeName(), ECQL.toFilter(during)));
15. // basic spatio-temporal query with projection down to a few attributes
16. this.queries = Collections.unmodifiableList(queries);
17. } catch (CQLException e) {
18. throw new RuntimeException("Error creating filter:", e);
19. }
20. }
21. return queries;
22. }
本章中所有涉及到的命令必须是在按照第二章中的安装步骤正确安装以后方可使用。虽然命令行的方式相比Java API的方式更加便捷,但是这种方式的性能远远落后于Java API,因此在测试的时候可以使用命令行工具进行快捷调试,但是如果项目对性能要求比较高,依然建议使用Java API来进行开发工作。
基本格式如下:
1. geomesa-hbase --[Option] --[Param] ....
1.
Classpath
展示运行时的类路径
2.
Env
展示SimpleFeatureTypes和GeoMesa的转换器
命令
|
解释
|
-s, --sfts
|
解释一个特定的SimpleFeatureType
|
-c, --converters
|
解释一个特定的转换器
|
--describe-sfts
|
解释所有的SimpleFeatureypeType
|
--describe-converters
|
解释所有的转换器
|
--list-converters
|
列出所有可用的转换器
|
--list-sfts
|
列出所有type的名字
|
--format
|
格式化并输出SimpleFeatureType
|
--concise
|
渲染输出
|
--exclude-user-data
|
在输出中排除用户的数据
|
3.
Help
列出可用的命令
4.
Version
展示版本
5.
Version-remote
展示在集群中的geomesa版本
Schema的信息命令比较多,但是常用的命令并不多,此处列出几个比较常用的命令,其他命令参见官方文档:https://www.geomesa.org/documentation/user/cli/schemas.html
1.
Create-schema
生成新的SimpleFeatureType
命令
|
解释
|
-c, catalog *
|
这个目录是用来保存schema元数据信息的
|
-s, --spec *
|
生成特定的SimpleFeatureType
|
-f, --feature-name
|
生成的schema的名称
|
--dtg
|
设定为默认的时间的字段
|
2.
Delete-catalog
删除给定catalog当中的所有SimpleFeatureType
命令
|
解释
|
-c, catalog *
|
这个目录是用来保存schema元数据信息的
|
3.
Describe-schema
查看一个SimpleFeatureType中的所有属性信息
命令
|
解释
|
-c, catalog *
|
这个目录是用来保存schema元数据信息的
|
-f, --feature-name
|
schema的名称
|
GeoMesa支持多种文件格式的输入,例如文本(TSV、CSV),JSON,XML和Avro
命令
|
解释
|
-c, --catalog *
|
目录名称
|
-C, --convertor
|
Geomesa转换器名称
|
-s, --spec
|
SimpleFeatureType
|
-f, --feature-name
|
Schema的名称
|
-t, --threads
|
并发线程的数量
|
--input-format
|
输入的格式(csv、tsv、avro、shp、json etc)
|
--split-max-size
|
最大的切片大小
|
<files>..
|
输入的文件
|
此处规则比较复杂,功能也比较多样,参见官方文档:https://www.geomesa.org/documentation/user/cli/export.html
此命令涉及到cost-base strategy,geomesa-hbase并不支持,geomesa-accumulo支持,因此在此不再详述,详情参看官方文档:https://www.geomesa.org/documentation/user/cli/analytic.html
网上现成的案例非常少,尤其是利用命令行进行文件数据导入导出的更加少。主要是华为云CloudTable的示例,但是这个示例有一些问题,无法测通,因此在这里选择了另一个国外的案例,能够测通,而且通过这个案例,能够对sft和convertor进行更加深入的理解。
1.
文档内容
1. 151001000015660,1001001,-1,55.476868,-25.874775,0.4,50,-999.9,511,2015-10-01 06:14:33,1
2. 151001000015661,1001001,-1,55.476868,-25.874775,0.4,50,-999.9,511,2015-10-01 06:14:34,1
3. 151002008706375,1001001,-1,55.82175,-26.442037,0.7,40,-999.9,511,2015-10-02 05:12:46,1
4. 151002008706376,1001001,-1,55.82175,-26.442037,0.7,40,-999.9,511,2015-10-02 05:12:47,1
2.
创建.sft文件
创建GeoMesa的SimpleFeatureType的配置文件,并将其命名为ais_data_conf.sft
1. geomesa.sfts.ais-data = {
2. attributes = [
3. { name = "arkposid", type = "Long", index = true }
4. { name = "mmsi", type = "Integer", index = false }
5. { name = "navigationalstatus", type = "Integer", index = false }
6. { name = "coords", type = "Point", index = true, srid = 4326, default = true }
7. { name = "sog", type = "Double", index = false }
8. { name = "cog", type = "Double", index = false }
9. { name = "rot", type = "Double", index = false }
10. { name = "heading", type = "Integer", index = false }
11. { name = "acquisitiontime", type = "String", index = false }
12. { name = "iptype", type = "Integer", index = false }
13. ]
14. }
3.
创建.convert文件
创建GeoMesa的Converter的配置文件,并将其命名为ais_data_feature_conf.convert
1. geomesa.converters.ais-data = {
2. type = "delimited-text",
3. format = "CSV",
4. id-field = "toString($arkposid)",
5. fields = [
6. { name = "arkposid", transform = "$1::long" }
7. { name = "mmsi", transform = "$2::int" }
8. { name = "navigationalstatus", transform = "$3::int" }
9. { name = "lon", transform = "$4::double" }
10. { name = "lat", transform = "$5::double" }
11. { name = "coords", transform = "point($lon, $lat)" }
12. { name = "sog", transform = "$6::double" }
13. { name = "cog", transform = "$7::double" }
14. { name = "rot", transform = "$8::double" }
15. { name = "heading", transform = "$9::int" }
16. { name = "acquisitiontime", transform = "toString($10)" }
17. { name = "iptype", transform = "$11::int" }
18. ]
19. }
4.
插入数据
执行geomesa-hbase命令来将csv文件当中的数据插入到Hbase当中
1. geomesa-hbase ingest \
2. -c ais \
3. -s /tmp/ais_data_conf.sft \
4. -C /tmp/ais_data_feature_conf.convert \
5. /tmp/sample.csv
5.
回传结果
如果出现下列结果,说明插入数据执行成功
1. <code>INFO Creating schema 'ais-data'
2. INFO Running ingestion in local mode
3. INFO Ingesting 1 file with 1 thread
4. [============================================================] 100% complete 4 ingested 0 failed in 00:00:01
5. INFO Local ingestion complete in 00:00:01
6. INFO Ingested 4 features and failed to ingest 0 feature.
1.
CQL/ECQL简述
CQL(Common Query Language,通用查询语言)是OGC为目录web服务规范创建的查询语言,不像基于XML的编码语言,CQL使用我们更熟悉的文本语法编写,具有更好的可读性和适应性。更多关于Geoserver中CQL的使用说明,参考CQL And ECQL。CQL的使用,要求属性在比较运算符的左边,基于此,Geoserver提供了扩展的CQL即ECQL,它提供了一种更类似于SQL的灵活语言。
2.
基本规则
1)
比较运算符包括: =,<>,>,>=,<,<=,如要选取人口大于1500万的洲,条件为PERSONS>15000000,其中PERSONS为人口数量的字段
2)
BETWEEN表示从一个范围到另一个范围,如PERSONS
BETWEEN 1000000 AND 3000000。
3)
比较运算符支持文本值,可在运算符=的右侧指定文本值,如 STATE_NAME='California',表示选择加利福尼亚州;也可以使用LIKE操作符,与SQL中的用法一样,如 STATE_NAME LIKE 'N%'会选择所有以N开头的州。
4)
对两个属性进行比较,如 MALE > FEMALE,选择男性多余女性的州。
5)
算术表达式可以使用 +, -, *, /构成,过滤条件 UNEMPLOY/(EMPLOYED + UNEMPLOY) > 0.07选择所有失业率大于7%的州。
6)
使用IN操作符,可选择属性在给定值范围内的,与SQL用法相同,如 ID IN ('states.1', 'states.12'),或查找名字在给定值内的州,可使用
STATE_NAME IN ('New York','California', 'Texas')。
7)
可使用Geoserver中的任何过滤函数,如 strToLowerCase(STATE_NAME) like '%m%',表示名字中包含m的州,不区分M的大小写。
8)
几何过滤,使用BBOX,如 BBOX(the_geom, -90, 40, -60, 45)表示选择在(-90, 40, -60,
45)范围内的州。
3.
时间谓词
句法
|
描述
|
表达式+BEFORE+时间
|
在某个时间点之前的数据
|
表达式+时间段+BEFORE OR DURING
|
在时间段之前或者在其中的数据
|
表达式+DURING+时间段
|
在一段时间内的时间值
|
表达式+时间+DURING OR AFTER
|
在一段时间段内的或者在此之后的数据
|
表达式+AFTER+时间
|
在某个时间点之后的数据
|
4.
空间谓词
句法
|
描述
|
INTERSECTS(表达式,表达式)
|
两个图形是否相交
|
DISJOINT(表达式,表达式)
|
两个图形是否不相交
|
CONTAINS(表达式,表达式)
|
第一个图形是否包含第二个
|
WITHIN(表达式,表达式 )
|
第一个图形是否在第二个内
|
TOUCHES(表达式,表达式 )
|
两个图形是否接触
|
CROSSES(表达式,表达式 )
|
两个图形是否交叉
|
OVERLAPS(表达式,表达式 )
|
两个图形是否重叠
|
EQUALS(表达式,表达式 )
|
两个图形是否相同
|
RELATE( 表达式,表达式 , 模式)
|
两个图形是否具有由DE-91M矩阵模式指定的空间关系
|
DWITHIN( 表达式,表达式 , 距离 , 单位 )
|
两个图形之间的距离是否不超过指定的距离
|
BEYOND( 表达式,表达式 , 距离 , 单位 )
|
两个图形之间的距离超过指定的距离
|
BBOX ( 表达式 , 数 , 数 , 数, 数 [, CRS ])
|
在指定的Bounding Box内的数据
|
5.
DE-9IM
DE-9IM,全称是Dimensionally Extended nine-Intersection Model (DE-9IM),是一种拓扑模型,用于描述两个几何图形空间关系的一种标准。在专业领域,通常将每个几何图形分为三部分:外部(exterior),边界(boundary)和内部(interior)。相像一下,一个矩形的三个部分分别是指哪些地方?两个图形的关系判断,实际上就是三个部分的分别判断,因此就会有一个3*3交叉矩阵,这个矩阵就是DE-9IM模型。
附录2 GeoMesa当中支持的Simple Feature
Types对照表
属性类型
|
绑定类
|
是否能够作为索引
|
String
|
java.lang.String
|
Yes
|
Integer
|
java.lang.Integer
|
Yes
|
Double
|
java.lang.Double
|
Yes
|
Long
|
java.lang.Long
|
Yes
|
Float
|
java.lang.Float
|
Yes
|
Boolean
|
java.lang.Boolean
|
Yes
|
UUID
|
java.util.UUID
|
Yes
|
Date
|
java.util.Date
|
Yes
|
Timestamp
|
java.sql.Timestamp
|
Yes
|
Point
|
org.locationtech.jts.geom.Point
|
Yes
|
LineString
|
org.locationtech.jts.geom.LineString
|
Yes
|
Polygon
|
org.locationtech.jts.geom.Polygon
|
Yes
|
MultiPoint
|
org.locationtech.jts.geom.MultiPoint
|
Yes
|
MultiLineString
|
org.locationtech.jts.geom.MultiLineString
|
Yes
|
MultiPolygon
|
org.locationtech.jts.geom.MultiPolygon
|
Yes
|
GeometryCollection
|
org.locationtech.jts.geom.GeometryCollection
|
Yes
|
Geometry
|
org.locationtech.jts.geom.Geometry
|
Yes
|
List[A]
|
java.util.List<A>
|
Yes
|
Map[A,B]
|
java.util.Map<A, B>
|
No
|
Bytes
|
byte[]
|
No
|