开发者社区 > 博文 > GIS实践篇——改写Ecql
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

GIS实践篇——改写Ecql

  • 京东城市JUST团队
  • 2021-01-12
  • IP归属:未知
  • 687浏览

1. Ecql概述

CQL(通用查询语言)是为OGC目录规范创建的纯文本语言。GeoServer已将其调整为易于使用的过滤机制。GeoServer实际上实现了一个名为ECQL(Extended CQL)的功能更强大的扩展,它允许表达OGC Filter1.1可以编码的所有过滤器

而geotools对于Ecql的解析有一套基于FilterFactory的解析机制,通过这套机制,可以生成语法解析树。

2. FilterFactory体系

FilterFactory体系结构如下:

FilterFactory体系最上层为FilterFactory接口,定义了Ecql当中所有的过滤方法,整理如下:

分类过滤方法
逻辑关系and、or、not、isNull
属性赋值id、property
比较关系between、equal、notequal、greater、greaterOrEqual、less、lessOrEqual
模糊查询like
空间查询bbox、beyond、contains、crosses、disjoint、dwithin、equals、intersects、overlaps、touches、with
时间查询after、anyIntersects、before、begins、begunBy、during、endBy、ends、meets、metBy、overlappedBy、toverlaps、tcontains、tequals
表达式add、divide、multiply、subtract、function、literal
排序sort

而FilterFactory2是继承了FilterFactory的一个接口,这个接口是为了能够更好地扩展FilterFactory的功能。FilterFactory只是对于真实的查询对象进行了描述,而在FilterFactory2中,将每个查询对象封装成为了具体的Expression,而Expression体系则通过访问者模式,实现了更为复杂的查询样式。

例如:crosses方法,在FilterFactory接口当中,局部变量定义为具体的String类型以及Geometry类型。

  1. /** Checks if the the first geometric operand contains the second. */
  2. Contains contains(String propertyName, Geometry geometry);
  3. /** Checks if the the first geometric operand contains the second. */
  4. Contains contains(String propertyName, Geometry geometry, MatchAction matchAction);

在FilterFactory2接口当中,则对于这个方法进行了扩展,将局部变量封装成为了Expression对象:

  1. /** Checks if the the first geometric operand contains the second. */
  2. Contains contains(Expression geometry1, Expression geometry2);
  3. /** Checks if the the first geometric operand contains the second. */
  4. Contains contains(Expression geometry1, Expression geometry2, MatchAction matchAction);

这样能够让相关的查询类支持更加复杂的查询条件。

FilterFactory2的两个实现类为FilterFactoryImpl和FastFilterFactory,二者都对于上述接口的方法进行了具体的实现。FilterFactoryImpl是更为通用的一种方式,而FastFilterFactory类则有一些查询优化的机制,可以使得查询更为高效。但是FastFilterFactory类是私有类,因此无法进行继承和开发,所以在此案例当中,通过自定义的FilterFactoryImpl子类来完成Ecql的改写工作。

在这两个方法当中,还有两个细节需要注意的。

一个是MatchAction参数,这个参数定义了对于两个表达式进行比对时,满足条件的情况。如下图所示,在ecql当中,对于两个条件进行比对时,两个条件可能会有多个子条件,例如A条件有n种情况,B条件又m种情况,对于每种情况可能会有n*m种比对的过程。我们可以设定MatchAction参数来控制其匹配的规则,MatchAction有三个状态:ANY、ALL、ONE,当我们设置为ANY时,表示只要这n*m种情况,有一种以上满足条件就为true;当我们设置为ALL时,表示这n*m种情况需要全部满足才能为true;当我们设置为ONE时,表示这些情况只能有一种满足,才为true。

另一个细节就是matchCase参数,这个参数主要是为了控制查询条件是否对大小写敏感。

3. 改写实践

新建一个TestFilterFactory类,继承FilterFactoryImpl类,重写其中的方法,在其中添加判断条件,此处展示的是比较简单的样例,如果需要更为复杂的改写,也可以再次写相关的更加复杂的逻辑。

  1. import org.geotools.filter.{AttributeExpressionImpl, FilterFactoryImpl}
  2. import org.opengis.filter.expression.Expression
  3. import org.opengis.filter.spatial.Within
  4. class TestFilterFactory extends FilterFactoryImpl{
  5. override def within(geometry1: Expression, geometry2: Expression): Within = {
  6. val e1 = if (geometry1.toString == "aaa") new AttributeExpressionImpl("bb") else geometry1
  7. super.within(e1, geometry2)
  8. }
  9. }

在最终调用这个类时,需要用到ECQL类的静态方法,将ecql利用自定义的Factory来进行转化。

  1. val ecql = "WITHIN(aaa, POLYGON ((116.54 39.75, 116.54 40, 117 40, 117 39.75, 116.54 39.75)))"
  2. val ff = new TestFilterFactory
  3. val filter = ECQL.toFilter(ecql, ff)
  4. val resultEcql = ECQL.toCQL(filter)

最后输出的就是改造过后的ecql语句了,已将aaa换成了bb

WITHIN(bb, POLYGON ((116.54 39.75, 116.54 40, 117 40, 117 39.75, 116.54 39.75)))
共0条评论