带有geo_distance过滤器的ElasticSearch MapperParsingExceptionn

时间:2014-08-27 09:06:55

标签: grails elasticsearch

我在我的应用程序中使用了grails elasticsearch插件,而且我遇到了一个奇怪的例外。

我有一种使用geo_distance过滤器构建请求的方法:

def activityList = ElasticSearchService.search(
            [types:[DomainA, DomainB],
            sort: orderBy, order: orderAs, size: (int)maxRes],
                {
                    // bla bla bla some working closure building a working query

                    }

                    if(centerLat != -1){
                        filter{
                            geo_distance(
                                'distance': searchRadius,
                                'activityLocation': [lat: (Double)centerLat, lon: (Double)centerLon]
                                )
                        }
                    }
                }
            )

每当我尝试将该方法与过滤器一起使用时(例如,当我将searchRadius设置为'5km'centerLat / centerLon以更正坐标时,我的ElasticSearch节点变得疯狂,并一直记录以下错误,直到我关闭它:

| Error 2014-08-27 10:31:49,076 [elasticsearch[Agent Zero][bulk][T#2]] ERROR index.IndexRequestQueue  - Failed bulk item: MapperParsingException[failed to parse]; nested: ElasticsearchParseException[field must be either 'lat', 'lon' or 'geohash']; 

我试着浏览一下这个MappingParserException被抛出的原因,最后我查看了org.elasticsearch.common.geo.GeoUtils类的source code。 Apparenty,抛出异常是因为我的latlon字段不是数字(请参阅第372行和381行)。

为什么会这样?我是否声明我的过滤器错误了?

4 个答案:

答案 0 :(得分:0)

我认为你的索引类型映射存在问题,为了理解你要发布索引的数据示例和类型映射的问题是什么(你可以从主机获取当前的映射:port / {索引} / _映射/ {类型})。 尝试按照此处的说明定义映射:http://noamt.github.io/elasticsearch-grails-plugin/guide/mapping.html查看3.3.2 GeoPoint,确保正确定义数据点。

答案 1 :(得分:0)

假设activityLocation的映射是" geo_point"那么你不应该用" lat"来表示你的coordindate。和" lon"并且应该能够发送

'activityLocation': [(Double)centerLat,(Double)centerLon]

我认为这是" lat" " LON"在早期版本中,preface可能已被支持为geo_point格式,但从1.0.0开始,我不认为它仍然存在。

答案 2 :(得分:0)

已经有一段时间了,这个问题让我感到很紧张,但我终于解决了。

我正在以这种方式映射以下类:

class A{

static searchable={
    activityLocation geoPoint:true, component:true
    // some other mappings on some other fields
}

Location activityLocation

// some other fields

}
a
class Location{
    static searchable = true

    String locationName

    Double lat

    Double lon
}

有两个问题:

  1. 在映射我的root false对象时,我不想使用activityLocation选项,因为我希望能够直接搜索它们,这导致我的{{1} }对象包含以下属性(请注意A字段的存在):

    id

  2. 不是'activityLocation' : { 'id':'1', 'locationName' : 'foo', 'lat': '42.5464', 'lon': '65.5647' },因为它不仅仅包含geoPointlat字段。

    1. 我将lon属性映射为locationName个对象的一部分,这使得 activityLocation
    2. 我最终通过将映射更改为geoPoint的以下值来解决问题:

      activityLocation

      这解决了我的问题,从那时起我的搜索进展顺利。

      我必须补充一点,我对这方面的文档感到非常困惑,我有点失望,因为我无法映射具有更多属性的ActivityLocation{ static searchable = { only = ['lat', 'lon'] root false } String locationName Double lat Double lon } 。我希望映射中还有其他字段。

      此外,我希望插件能让我更好地访问ES日志,我花了一些时间来找出查找错误代码的位置。

答案 3 :(得分:0)

I have managed to fix this with few lines of coded added to "DeepDomainClassMarshaller.groovy" and overriding this file. 

Previous code:-
if (DomainClassArtefactHandler.isDomainClass(propertyClass)) {
                String searchablePropertyName = getSearchablePropertyName()
                if (propertyValue.class."$searchablePropertyName") {
                    // todo fixme - will throw exception when no searchable field.
                    marshallingContext.lastParentPropertyName = prop.name
                    marshallResult += [(prop.name): ([id: propertyValue.ident(), 'class': propertyClassName] + marshallingContext.delegateMarshalling(propertyValue, propertyMapping.maxDepth))]
                } else {
                    marshallResult += [(prop.name): [id: propertyValue.ident(), 'class': propertyClassName]]
                }

                // Non-domain marshalling
            }

New Code:-
if (DomainClassArtefactHandler.isDomainClass(propertyClass)) {
                String searchablePropertyName = getSearchablePropertyName()
                if (propertyValue.class."$searchablePropertyName") {
                    // todo fixme - will throw exception when no searchable field.
                    marshallingContext.lastParentPropertyName = prop.name
                    if(propertyMapping?.isGeoPoint())
                        marshallResult += [(prop.name): (marshallingContext.delegateMarshalling(propertyValue, propertyMapping.maxDepth))]
                    else
                        marshallResult += [(prop.name): ([id: propertyValue.ident(), 'class': propertyClassName] + marshallingContext.delegateMarshalling(propertyValue, propertyMapping.maxDepth))]
                } else {
                    marshallResult += [(prop.name): [id: propertyValue.ident(), 'class': propertyClassName]]
                }

                // Non-domain marshalling
            }

Let me know in case issue still persists.

Note:- I am still using elasticsearch:0.0.3.3.