如何访问在 Elasticsearch 上使用 NEST 进行的查询中的脚本字段?
How can I access script fields in queries made with NEST on Elasticsearch?
我有一个具有坐标字段的 POCO,并且使用 NEST 的映射和地理距离搜索都按预期工作。但是,我试图用 NEST 做的是 return 与 GeoDistance 查询中指定的点的距离作为搜索结果的一部分。到目前为止,我的研究表明有两种方法可以做到这一点:
- request a sort on the location
- 创建脚本字段作为查询的一部分,运行内联距离计算
我决定 运行 使用选项 2,部分代码如下所示:
public class User
{
public int ID { get; set; }
[GeoPoint]
public Coordinate Location { get; set; }
}
查询本身:
var results = elasticClient.Search<User>(s => s
.Index("user")
.Query(q => q
.GeoDistance(gd => gd
.Field(f => f.Location)
.Distance(Distance.Miles(distance))
.Location(GeoLocation.TryCreate(data.Latitude, data.Longitude))
) && q
.Exists(e => e
.Field("location")
)
)
.ScriptFields(sf => sf
.ScriptField("distance", sf2 => sf2
.Inline(String.Format("doc['location'].arcDistance({0},{1})", data.Latitude, data.Longitude))
.Lang("painless")
)
)
);
虽然 运行 直接针对 elasticsearch 执行此查询似乎没问题,但当我在 NEST 中执行此操作时,我遇到了一些问题:
- 我无法访问我在 POCO 对象中定义的 "distance" 脚本字段,除非我将它添加到定义中
- 如果我为用户 POCO 创建一个子class,ElasticSearch 不会反序列化父 class 中定义的字段(这意味着我只得到距离脚本字段,而不是 ID 或Location字段,Documents数组对象均为Null)
- 我试图在我用于映射的实际 POCO 和搜索结果对象之间保持分离,但我不知道如何标记属性/字段以便 NEST 不会映射它,但会将脚本字段的结果反序列化为 属性
我的问题是:在 NEST 中访问脚本字段的推荐方法是什么?我必须完全放弃自动映射吗?或者即使我不是特别想对结果进行排序,我也应该选择排序选项吗?
我最终通过以下方式接近了我想要的:
- 明确告诉我的查询包含 _source 存储字段 - 似乎不会返回 if you use any script fields you need to do this 或 _source / documents。
- 将
[ElasticsearchType(Name = "User")]
属性添加到我的搜索结果子类中
枚举结果中的 Hits
时,访问我的脚本字段:
((JArray)item.Fields["distance"]).Value<double>(0) / 1609.344
如果有人有更简洁的方法,请告诉我!
使用 ValueOf 方法有一个更清晰的方法。
例子
item.Fields.ValueOf<User, string>(p => p.Distance)
我有一个具有坐标字段的 POCO,并且使用 NEST 的映射和地理距离搜索都按预期工作。但是,我试图用 NEST 做的是 return 与 GeoDistance 查询中指定的点的距离作为搜索结果的一部分。到目前为止,我的研究表明有两种方法可以做到这一点:
- request a sort on the location
- 创建脚本字段作为查询的一部分,运行内联距离计算
我决定 运行 使用选项 2,部分代码如下所示:
public class User
{
public int ID { get; set; }
[GeoPoint]
public Coordinate Location { get; set; }
}
查询本身:
var results = elasticClient.Search<User>(s => s
.Index("user")
.Query(q => q
.GeoDistance(gd => gd
.Field(f => f.Location)
.Distance(Distance.Miles(distance))
.Location(GeoLocation.TryCreate(data.Latitude, data.Longitude))
) && q
.Exists(e => e
.Field("location")
)
)
.ScriptFields(sf => sf
.ScriptField("distance", sf2 => sf2
.Inline(String.Format("doc['location'].arcDistance({0},{1})", data.Latitude, data.Longitude))
.Lang("painless")
)
)
);
虽然 运行 直接针对 elasticsearch 执行此查询似乎没问题,但当我在 NEST 中执行此操作时,我遇到了一些问题:
- 我无法访问我在 POCO 对象中定义的 "distance" 脚本字段,除非我将它添加到定义中
- 如果我为用户 POCO 创建一个子class,ElasticSearch 不会反序列化父 class 中定义的字段(这意味着我只得到距离脚本字段,而不是 ID 或Location字段,Documents数组对象均为Null)
- 我试图在我用于映射的实际 POCO 和搜索结果对象之间保持分离,但我不知道如何标记属性/字段以便 NEST 不会映射它,但会将脚本字段的结果反序列化为 属性
我的问题是:在 NEST 中访问脚本字段的推荐方法是什么?我必须完全放弃自动映射吗?或者即使我不是特别想对结果进行排序,我也应该选择排序选项吗?
我最终通过以下方式接近了我想要的:
- 明确告诉我的查询包含 _source 存储字段 - 似乎不会返回 if you use any script fields you need to do this 或 _source / documents。
- 将
[ElasticsearchType(Name = "User")]
属性添加到我的搜索结果子类中 枚举结果中的
Hits
时,访问我的脚本字段:((JArray)item.Fields["distance"]).Value<double>(0) / 1609.344
如果有人有更简洁的方法,请告诉我!
使用 ValueOf 方法有一个更清晰的方法。 例子
item.Fields.ValueOf<User, string>(p => p.Distance)