ElasticSearch源码 - GeoPoint

elasticsearch 5.4.3

最近在研究es 地理信息相关的接口,目前来说es提供俩种geo相关的类型:GeoPoint 和GeoShape两种。这里我只研究一下GeoPoint。该类型在V_5_0_0_alpha1版本进行了重大的改动。首先我们看一下这个类型的整个结构:

父类:BaseGeoPointFieldMapper
子类:
1. GeoPointFieldMapper :适用于2.2.0-4.0.0之间的版本
2. LegacyGeoPointFieldMapper:适用于2.2.0版本
3. LatLonPointFieldMapper:适用于4.0.0之后的版本

具体我们可以看一下BaseGeoPointFieldMapper$TypeParser::parse()函数,在索引文当时会首先判断索引创建的版本,然后在根据版本号决定适使用哪个版本的geo_point.

Version indexVersionCreated = parserContext.indexVersionCreated();
            if (indexVersionCreated.before(Version.V_2_2_0)) {
                builder = new LegacyGeoPointFieldMapper.Builder(name);
            } else if (indexVersionCreated.onOrAfter(LatLonPointFieldMapper.LAT_LON_FIELD_VERSION)) {
                builder = new LatLonPointFieldMapper.Builder(name);
            } else {
                builder = new GeoPointFieldMapper.Builder(name);
            }

BaseGeoPointFieldMapper

GeoPointFieldMapper base class to maintain backward compatibility

首先来看对于geopoint的默认配置:

 public static class Defaults {
        public static final boolean ENABLE_LATLON = false;
        public static final boolean ENABLE_GEOHASH = false;
        public static final boolean ENABLE_GEOHASH_PREFIX = false;
        public static final int GEO_HASH_PRECISION = GeoHashUtils.PRECISION;
        public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
    }

虽然原始设置是这样的,但是如果你在配置的时候。通过如下方式配置geo_point的属性,是报错的,因为在5.0.0版本后已经屏蔽了这些参数

"location": {
                            "type": "geo_point",
                            "geohash_prefix":     true, 
         					 "geohash_precision":  "1km" 
                        },

接下来我们来看一下这三个类型的区别。

LegacyGeoPointFieldMapper

这个类型主要用于2.2.0的版本算是远古时期的了。

MappedFieldType geoHashFieldType;
MappedFieldType latFieldType;
MappedFieldType lonFieldType;

在远古版本的geo_point 在lucene并没有一个属于自己的类型,主要是拆分成了三个field进行索引存储。原始数据值是包含了经纬度的坐标值。为了建立geohash索引还会生成一个额外的field geohash,如

private void addGeoHashField(ParseContext context, String geoHash) throws IOException {
        LegacyGeoPointFieldType ft = (LegacyGeoPointFieldType)fieldType;
        int len = Math.min(ft.geoHashPrecision(), geoHash.length());
        int min = ft.isGeoHashPrefixEnabled() ? 1 : len;

        for (int i = len; i >= min; i--) {
            // side effect of this call is adding the field
            geoHashMapper.parse(context.createExternalValueContext(geoHash.substring(0, i)));
        }
    }

这个位置怪的很,他把每一位的geohash都保存了一个,为什么部直接用prefix来查呢??

这里的point在lucene里面采用的是binarydocalue的形式,我们可以看一下CustomGeoPointDocValuesField的实现:

       @verride
        public BytesRef binaryValue() {
            final byte[] bytes = new byte[points.size() * 16];
            int off = 0;
            for (Iterator<ObjectCursor<GeoPoint>> it = points.iterator(); it.hasNext(); ) {
                final GeoPoint point = it.next().value;
                ByteUtils.writeDoubleLE(point.getLat(), bytes, off);
                ByteUtils.writeDoubleLE(point.getLon(), bytes, off + 8);
                off += 16;
            }
            return new BytesRef(bytes);
        }

这一点在GeoPointFieldMapper会有较大的变动。

GeoPointFieldMapper

这个类型适用与2.2.0至4.0.0的版本, 到底会被转换成geo_point进行处理。

这个属性在lucene底层会以GeoPointField存储。

@Override
    protected void parse(ParseContext context, GeoPoint point, String geoHash) throws IOException {
		....
        if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) {
            context.doc().add(new GeoPointField(fieldType().name(), point.lat(), point.lon(), fieldType()));
        }
        super.parse(context, point, geoHash);
    }

LatLngPointFieldMapper

这个类型适用4.0.0以上的版本。
我们来看一下Parse函数

if (fieldType().indexOptions() != IndexOptions.NONE) {
            context.doc().add(new LatLonPoint(fieldType().name(), point.lat(), point.lon()));
        }
        if (fieldType().stored()) {
            context.doc().add(new StoredField(fieldType().name(), point.toString()));
        }
        if (fieldType.hasDocValues()) {
            context.doc().add(new LatLonDocValuesField(fieldType().name(), point.lat(), point.lon()));
        }
        // if the mapping contains multifields then use the geohash string
        if (multiFields.iterator().hasNext()) {
            multiFields.parse(this, context.createExternalValueContext(point.geohash()));
        }

首先来说,经纬度的索引形式采用的是LatLonPoint,而若开始docalue时,则采用LatLonDocValuesField,此外他还支持multifield。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值