D_Inventor
08/08/2023, 8:21 AMDistanceUtils.Dist2Degrees(distance, DistanceUtils.EARTH_MEAN_RADIUS_KM)
and I verified that the mean radius in kilometers is correctSebastiaan
08/08/2023, 9:35 AMBjarne Fyrstenborg
08/08/2023, 11:25 AMGeoLocationFieldName
is... I guess it was a field set in Lucene document writing event using same strategy as when searching.Bjarne Fyrstenborg
08/08/2023, 11:29 AMpublic void Initialize()
{
if (!_examineManager.TryGetIndex("ExternalIndex", out IIndex cindex))
{
throw new InvalidOperationException($"No index found by name ExternalIndex");
}
if (cindex is not LuceneIndex luceneIndex)
{
throw new InvalidOperationException($"Index ExternalIndex is not a LuceneIndex.");
}
SpatialContext ctx = SpatialContext.Geo;
int maxLevels = 11; //results in sub-meter precision for geohash
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);
var strategy = new RecursivePrefixTreeStrategy(grid, Constants.Examine.CourseInstance.FieldNames.GeoLocation);
luceneIndex.DocumentWriting += (sender, args) => LuceneIndex_DocumentWriting(args, ctx, strategy);
}
private void LuceneIndex_DocumentWriting(DocumentWritingEventArgs e, SpatialContext ctx, SpatialStrategy strategy)
{
if (e.Document.GetField("latitude") == null ||
e.Document.GetField("longitude") == null)
return;
double latitude = double.Parse(e.ValueSet.Values["latitude"].First().ToString() ?? string.Empty, CultureInfo.InvariantCulture);
double longitude = double.Parse(e.ValueSet.Values["longitude"].First().ToString() ?? string.Empty, CultureInfo.InvariantCulture);
GetXYFromCoords(latitude, longitude, out var x, out var y);
IPoint geoPoint = ctx.MakePoint(x, y);
foreach (Field field in strategy.CreateIndexableFields(geoPoint))
{
e.Document.Add(field);
}
// I don't think this stored field is necessary to use spartial search, but is shown in Examine dashboard.
e.Document.Add(new StoredField(strategy.FieldName, Invariant($"{geoPoint.X} {geoPoint.Y}")));
}
private void GetXYFromCoords(double lat, double lng, out double x, out double y)
{
// Important! we need to change to x/y coords, longitude = x, latitude = y
x = lng;
y = lat;
}
https://gist.github.com/bjarnef/6b427123903c90e034027bb8a3a5d43aCodeSharePaul
08/08/2023, 11:41 AMCodeSharePaul
08/08/2023, 11:41 AMcs
var index = (LuceneIndex)_examineManager.GetIndex(Constants.ExamineIndexes.WMNIndex);
var query = (LuceneSearchQueryBase)index.Searcher.CreateQuery(null, BooleanOperation.Or);
var searcher = new IndexSearcher(index.IndexWriter.IndexWriter.GetReader(false));
var filteredQuery = index
.Searcher
.CreateQuery()
.NativeQuery($"+__IndexType:{IndexTypes.Content}")
.And()
.GroupedOr(new[] { "__NodeTypeAlias" }, searchModel.ContentTypes.ToArray());
if (!string.IsNullOrWhiteSpace(searchModel?.SearchQuery?.Phrase ?? ""))
{
filteredQuery
.And()
.GroupedAnd(new[] { "name" }, searchModel.SearchQuery.Terms);
}
if (searchModel?.FacetSets != null && searchModel.FacetSets.Any())
{
foreach (var facetSet in searchModel.FacetSets)
{
if (facetSet.SelectedValues != null && facetSet.SelectedValues.Any())
{
filteredQuery.And()
.GroupedOr(new[] { facetSet.PropertyAlias }, facetSet.SelectedValues);
}
}
}
CodeSharePaul
08/08/2023, 11:41 AMcs
Match match = Regex.Match(filteredQuery.ToString(), @"LuceneQuery:(.*?)\}");
if (match.Success)
{
string luceneQuery = match.Groups[1].Value.Trim();
var filterLuceneQuery = query.QueryParser.Parse(luceneQuery);
query.Query.Add(filterLuceneQuery, Occur.MUST);
}
var field = new SortField("score", SortFieldType.SCORE, true);
var sort = new Sort(field);
var hasLocationPoint = !string.IsNullOrWhiteSpace(searchModel.Longitude) && !string.IsNullOrWhiteSpace(searchModel.Latitude);
if (hasLocationPoint)
{
BooleanQuery geoQuery = null;
var valueType = (ShapeFieldValueType)index.FieldValueTypeCollection.ValueTypes
.FirstOrDefault(x => x.FieldName == "locations");
var circleQuery = valueType.Strategy.MakeQuery(
new SpatialArgs(
SpatialOperation.Intersects,
valueType.Context.MakeCircle(
double.Parse(searchModel.Longitude),
double.Parse(searchModel.Latitude),
DistanceUtils.Dist2Degrees(searchModel.RadiusInMiles, DistanceUtils.EarthMeanRadiusMiles))
)
);
var shouldOrMust = searchModel.RestrictResultsToDistance ? Occur.MUST : Occur.SHOULD;
geoQuery = new BooleanQuery();
geoQuery.Add(circleQuery, shouldOrMust);
if (geoQuery != null)
{
query.Query.Add(geoQuery, shouldOrMust);
}
}
var result = searcher.Search(query.Query, searchModel.MaxResults, sort);
CodeSharePaul
08/08/2023, 11:42 AMBjarne Fyrstenborg
08/08/2023, 11:47 AMDoSpatialSearch()
method.
and handle sorting by distance here: https://gist.github.com/bjarnef/6b427123903c90e034027bb8a3a5d43a#file-searchservice-cs-L67D_Inventor
08/08/2023, 12:01 PMD_Inventor
08/08/2023, 12:06 PMEarthMeanRadiusKilometers
for the radius.CodeSharePaul
08/08/2023, 12:07 PM