您的位置:首页 > 其它

ElasticsearchCRUD使用(十三)【Elasticsearch谷歌地图搜索的MVC应用】

2017-05-11 22:47 465 查看
本文介绍如何创建一个使用谷歌地图和Elasticsearch的MVC应用程序进行geo_distance搜索,并找到最近的点(文档)到您的位置。

Elasticsearch索引使用geo_point来定义每个文档的位置。Elasticsearch支持GeoJson格式。

Elasticsearch索引和类型使用以下模型创建:

public class MapDetail
{
public long Id { get; set; }

public string Name { get; set; }

public string Details { get; set; }

public string Information { get; set; }

public string DetailsType { get; set; }

[ElasticsearchGeoPoint]
public GeoPoint DetailsCoordinates { get; set; }
}


DetailsCoordinates
属性使用
GeoPoint
类,用于
geo_distance
搜索。 Elasticsearch中的映射使用ElasticsearchCRUD的
IndexCreate
方法创建。 Elasticsearch中的Geo类型如果是
geo_point
,则需要一个
ElasticsearchGeoPoint
属性,如果它是一个shape 类型,则需要一个
ElasticsearchGeoShape
属性。 必须映射
Geo
属性,并在索引新文档时不能自动创建。

public void InitMapDetailMapping()
{
using (var context = new ElasticsearchContext(
ConnectionString,
new ElasticsearchSerializerConfiguration(_elasticsearchMappingResolver)))
{
context.TraceProvider = new ConsoleTraceProvider();
context.IndexCreate<MapDetail>();
}
}


可以使用以下方式查看映射:

http://localhost:9200/_mapping




一旦创建了索引和类型,就会使用
_bulk
API添加一些数据。 这些文件都使用
SaveChanges()
方法发送。

public void AddMapDetailData()
{
var dotNetGroup = new MapDetail { DetailsCoordinates = new GeoPoint(7.47348, 46.95404), Id = 1, Name = ".NET User Group Bern", Details = "http://www.dnug-bern.ch/", DetailsType = "Work" };
var dieci = new MapDetail { DetailsCoordinates = new GeoPoint(7.41148, 46.94450), Id = 2, Name = "Dieci Pizzakurier Bern", Details = "http://www.dieci.ch", DetailsType = "Pizza" };
var babylonKoeniz = new MapDetail { DetailsCoordinates = new GeoPoint(7.41635, 46.92737), Id = 3, Name = "PIZZERIA BABYLON Köniz", Details = "http://www.pizza-babylon.ch/home-k.html", DetailsType = "Pizza" };
var babylonOstermundigen = new MapDetail { DetailsCoordinates = new GeoPoint(7.48256, 46.95578), Id = 4, Name = "PIZZERIA BABYLON Ostermundigen", Details = "http://www.pizza-babylon.ch/home-o.html", DetailsType = "Pizza" };
using (var context = new ElasticsearchContext(ConnectionString, new ElasticsearchSerializerConfiguration(_elasticsearchMappingResolver)))
{
context.TraceProvider = new ConsoleTraceProvider();
context.AddUpdateDocument(dotNetGroup, dotNetGroup.Id);
context.AddUpdateDocument(dieci, dieci.Id);
context.AddUpdateDocument(babylonKoeniz, babylonKoeniz.Id);
context.AddUpdateDocument(babylonOstermundigen, babylonOstermundigen.Id);
context.SaveChanges();
}
}


Elasticsearch中的索引和类型在
global.asax
Application_Start
方法中初始化。 这将检查索引是否存在,并创建一个新的索引(如果没有)。

private void InitSearchEngine()
{
var searchProvider = new SearchProvider();

if (!searchProvider.MapDetailsIndexExists())
{
searchProvider.InitMapDetailMapping();
searchProvider.AddMapDetailData();
}
}


使用
geo_distance
filter 和 query查询索引。 这将搜索最大距离内的所有文档,并从最接近您的搜索位置的升序排序命中结果。

{
"query" :
{
"filtered" : {
"query" : {
"match_all" : {}
},
"filter" : {
"geo_distance" : {
"distance" : "300m",
"detailscoordinates" : [7.41148,46.9445]
}
}
}
},
"sort" : [
{
"_geo_distance" : {
"detailscoordinates" : [7.41148,46.9445],
"order" : "asc",
"unit" : "m"
}
}
]
}
}


上面的Elasticsearch 查询看起来像这样在C#

var search = new Search
{
Query = new Query(
new Filtered(
new Filter(
new GeoDistanceFilter(
"detailscoordinates",
new GeoPoint(centerLongitude, centerLatitude),
new DistanceUnitMeter(maxDistanceInMeter)
)
)
)
{
Query = new Query(new MatchAllQuery())
}
),
Sort = new SortHolder(
new List<ISort>
{
new SortGeoDistance("detailscoordinates", DistanceUnitEnum.m)
{
Order = OrderEnum.asc
}
}
)
};


然后在HomeController中使用它,如下所示:

public ActionResult Search(int maxDistanceInMeter, double centerLongitude, double centerLatitude)
{
var searchResult = _searchProvider.SearchForClosest(maxDistanceInMeter, centerLongitude, centerLatitude);
var mapModel = new MapModel
{
MapData = new JavaScriptSerializer().Serialize(searchResult),
CenterLongitude = centerLongitude,
CenterLatitude = centerLatitude,
MaxDistanceInMeter = maxDistanceInMeter
};

return View("Index", mapModel);
}


razor 索引视图使用此数据在地图显示中。 使用绿色图像显示与您的搜索位置最接近的文档。 最大搜索距离内的所有命中也显示在地图中。 您可以移动您的中心位置,增加或减少最大允许距离,结果将被正确显示。

@*Bern  Lat 46.94792, Long 7.44461 *@
@model WebAppGeoElasticsearch.Models.MapModel

<input type="hidden" value="@Model.MapData" id="mapdata" name="mapdata" />

@using (Html.BeginForm("Search", "Home"))
{
<fieldset class="form">
<legend>SEARCH for closest document in the search engine using geo distance</legend>
<table width="800">
<tr>
<th></th>
</tr>
<tr>

</tr>
<tr>
<td>
<input type="submit" value="Search fo closest: " style="width: 300px">
</td>
<td>
<input type="hidden" value="@Model.CenterLongitude" id="centerLongitude" name="centerLongitude" />
<input type="hidden" value="@Model.CenterLatitude" id="centerLatitude" name="centerLatitude" />

</td>
<td>
<p style="width: 300px">Max distance in meter:</p>
<input id="maxDistanceInMeter" name="maxDistanceInMeter" type="text" title="" value="@Model.MaxDistanceInMeter" style="width: 200px" />
</td>
</tr>
</table>
</fieldset>

}

<div class="row">
@*Bern  Lat 46.94792, Long 7.44461 *@
<div id="googleMap" style="width: 1000px; height: 800px;">
</div>
</div>

@section scripts
{
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markermanager/src/markermanager.js"></script>

<script language="javascript" type="text/javascript">
var map;
var mgr;

function initialize() {
var myOptions = {
zoom: 13,
center: new google.maps.LatLng(46.94792, 7.44461),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("googleMap"), myOptions);
mgr = new MarkerManager(map);
var infoWindow = new google.maps.InfoWindow({ content: "contents" });
google.maps.event.addListener(mgr, 'loaded', function() {

var modelData = $.parseJSON($("#mapdata").val());

var first = true;
$.each(modelData, function(entryIndex, entry) {
//alert("Data" + entry.DetailsCoordinates + ", " + entry.Details);

var htmlString = "<a href=\"" + entry.Details + "\">" + entry.Name + "</a>";
var coor = entry.DetailsCoordinates.toString();
var array = coor.split(',');

// alert("Lat" + array[1] + "Long" + array[0]);
if (first) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(array[1], array[0]),
html: htmlString,
icon: "http://localhost:2765/Content/yourposition.png"
});

first = false;
} else {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(array[1], array[0]),
html: htmlString
});
}

google.maps.event.addListener(marker, "click", function() {
infoWindow.setContent(this.html);
infoWindow.open(map, this);
});

mgr.addMarker(marker, 0);

});

// alert('homemarker: ' + $("#centerLatitude").val() + ' Current Lng: ' + $("#centerLongitude").val());

var homemarker = new google.maps.Marker({

position: new google.maps.LatLng($("#centerLatitude").val(), $("#centerLongitude").val()),
html: "YOU",
draggable: true,
icon: "http://localhost:2765/Content/ort.png"
});

google.maps.event.addListener(homemarker, 'dragend', function(evt) {
// alert('Marker dropped: Current Lat: ' + evt.latLng.lat().toFixed(3) + ' Current Lng: ' + evt.latLng.lng().toFixed(3));
$("#centerLongitude").val(evt.latLng.lng().toFixed(3));
$("#centerLatitude").val(evt.latLng.lat().toFixed(3));
});

mgr.addMarker(homemarker, 0);

mgr.refresh();
});
}

google.maps.event.addDomListener(window, 'load', initialize);
</script>
}


搜索后的应用程序视图:



结论

您可以看到,使用Elasticsearch进行Geo搜索很容易。 支持一系列Geo搜索过滤器,地理边界框过滤器,地理距离过滤器,地理距离范围过滤器,地理多边形过滤器,GeoShape过滤器,Geohash信元过滤器(Geo Bounding Box Filter, Geo Distance Filter, Geo Distance Range Filter, Geo Polygon Filter, GeoShape Filter, Geohash Cell Filter)以及大多数geoJSON形状和GeoShape查询。 可以创建最优搜索以匹配大多数要求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: