NCache Lucene API를 기반으로 Lucene API를 구현하여 Lucene을 분산 및 확장 가능하게 만듭니다. NCache의 분산 아키텍처. 부터 NCache, NCache 다른 Lucene 기능인 GeoSpatial Indexes를 지원합니다. Distributed Lucene과 함께 GeoSpatial 인덱스를 사용하는 방법을 살펴보겠습니다.
Distributed Lucene을 사용한 전체 텍스트 검색은 인덱싱과 검색의 두 단계로 나뉩니다. 인덱싱 단계에서 분석기는 일부 텍스트에서 인덱스를 생성합니다. 그런 다음 검색 단계에서는 해당 인덱스만 사용합니다.
GeoSpatial Indexes로 작업하고 있기 때문에 문서의 경도 및 위도 좌표를 인덱싱한 다음 저장된 위치를 기반으로 데이터를 검색하려고 합니다.
분산 Lucene에서 GeoSpatial 인덱스를 사용하는 방법
지리 공간 좌표로 문서를 색인화하고 위치 기반 검색을 수행하기 위해 Distributed Lucene은 다음을 사용합니다. 공간4n, ".NET용 지리 공간 라이브러리."
샘플 애플리케이션을 시작하기 전에 NCache 설치되어 있고 분산 Lucene 캐시가 이미 생성되어 있습니다. 분산 Lucene 캐시를 구성하는 방법을 배우려면 다음을 확인하십시오. 지속성 캐시를 사용하여 분산 Lucene 만들기.
1. 일부 랜드마크 색인 생성
GeoSpatial Index를 사용하여 과거 여행에서 가장 좋아하는 랜드마크를 저장해 보겠습니다.
먼저 콘솔 애플리케이션을 만들고 NuGet 패키지를 설치해 보겠습니다. Lucene.Net.Spatial.NCache
.
에서, Program.cs
파일을 사용하여 파리 주변의 일부 랜드마크를 색인화해 보겠습니다. 각 랜드마크에는 이름, 경도 및 위도가 있습니다. 이 같은,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
using DistributedLucene.Net.Spatial; using Landmarks; using Lucene.Net.Analysis.Standard; using Lucene.Net.Index; using Lucene.Net.Spatial.Prefix; using Lucene.Net.Spatial.Prefix.Tree; using Lucene.Net.Store; using Lucene.Net.Util; using Spatial4n.Core.Context; const LuceneVersion LuceneVersion = LuceneVersion.LUCENE_48; const string CacheName = "DemoLuceneCache"; const string IndexName = "landmarks"; const string NameFieldName = "name"; const string LocationFieldName = "landmarkLocation"; // 1. Let's index some locations around Paris var favoriteLandmarks = new Landmark[] { new Landmark("Eiffel Tower", new Location(48.858093, 2.294694)), new Landmark("Sacre Coeur", new Location(48.886452, 2.343121)), new Landmark("Louvre Museum", new Location(48.860294, 2.338629)), new Landmark("Palace of Versailles", new Location(48.804722, 2.121782)), new Landmark("Disneyland Paris", new Location(48.867374, 2.784018)), new Landmark("Arc de Triomphe", new Location(48.873756, 2.294946)) }; IndexLandmarks(favoriteLandmarks); // Later, we will search all landmarks close to a reference point here... static void IndexLandmarks(IEnumerable landmarks) { // Create an SpatialStrategy var context = SpatialContext.GEO; var strategy = new RecursivePrefixTreeStrategy( new GeohashPrefixTree(context, maxLevels: 11), fieldName: LocationFieldName); // Open a directory using var indexDirectory = NCacheDirectory.Open(CacheName, IndexName); var config = new IndexWriterConfig(LuceneVersion, new StandardAnalyzer(LuceneVersion)) { OpenMode = OpenMode.CREATE }; // Create a writer using var writer = new IndexWriter(indexDirectory, config); foreach (var landmark in landmarks) { // Create a SpatialDocument from our Landmark var document = landmark.ToSpatialDocument(strategy); // Add a document writer.AddDocument(document, strategy); } // Write all documents writer.Commit(); } public record Location(double Latitude, double Longitude); public record Landmark(string Name, Location Position); |
익숙하다면 분산 Lucene을 사용한 전체 텍스트 인덱싱, GeoSpatial Indexes를 생성하는 것도 매우 유사합니다. 우리는 열어야 한다 NCache 디렉토리를 만들고 작성자를 만들고 작성자에 문서를 추가합니다.
그러나 분석기를 사용하여 텍스트를 인덱싱하는 대신 SpatialStrategy
. 전략은 점과 모양을 인덱싱 가능한 필드로 바꿉니다.
랜드마크를 색인화하기 위해 다음을 사용했습니다. RecursivePrefixTreeStrategy
. 이 전략은 점이 아닌 모양 검색을 지원합니다. 이를 생성하기 위해 Geohash 기반 트리와 필드 이름을 사용했습니다. 나중에 같은 필드 이름을 사용하여 문서를 만들 것입니다.
Distributed Lucene은 새로운 유형의 문서를 소개합니다. SpatialDocument
. 몇 가지 모양이 첨부된 Lucene 문서입니다. 점, 직사각형 또는 원과 같은 것입니다.
이것은 ToSpatialDocument()
랜드마크를 변환하는 데 사용한 확장 방법 SpatialDocument
,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using Lucene.Net.Documents; using Lucene.Net.Spatial; using Spatial4n.Core.Context; using static System.FormattableString; using Document = Lucene.Net.Documents.Document; namespace Landmarks; public static class LocationExtensions { public static SpatialDocument ToSpatialDocument(this Landmark landmark, SpatialStrategy strategy) { var document = new Document { new StringField("name", landmark.Name, Field.Store.YES) }; var point = SpatialContext.GEO.MakePoint(landmark.Position.Longitude, landmark.Position.Latitude); document.Add(new StoredField(strategy.FieldName, Invariant($"{point.X} {point.Y}"))); return new SpatialDocument { Document = document, Shapes = new[] { point } }; } } |
랜드마크 이름을 문자열 필드에 저장하고 랜드마크 위치의 문자열 표현을 다음 이름의 다른 필드에 저장했습니다. SpatialStrategy
분야 명. 그런 다음, 우리는 SpatialDocument
일반 Lucene 문서와 랜드마크 위치에 대한 포인트.
포인트를 만들기 위해 우리는 SpatialContext.GEO
생성자를 직접 사용하는 대신 팩토리.
2. 가장 가까운 랜드마크 검색
이제 우리가 가장 좋아하는 랜드마크를 인덱싱했으므로 파리 공항에서 30km 떨어진 곳에서 XNUMX곳을 찾아보겠습니다.
업데이트하자 Program.cs
포함할 파일 SearchAround()
방법,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
using DistributedLucene.Net.Spatial; using Landmarks; using Lucene.Net.Analysis.Standard; using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Spatial; using Lucene.Net.Spatial.Prefix; using Lucene.Net.Spatial.Prefix.Tree; using Lucene.Net.Spatial.Queries; using Lucene.Net.Store; using Lucene.Net.Util; using Spatial4n.Core.Context; using Spatial4n.Core.Distance; const LuceneVersion LuceneVersion = LuceneVersion.LUCENE_48; const string CacheName = "DemoLuceneCache"; const string IndexName = "landmarks"; const string NameFieldName = "name"; const string LocationFieldName = "landmarkLocation"; // 2. Let's find five landmarks, 30Km around the airport // and print them var airport = new Landmark("Charles de Gaulle Airport", new Location(49.009724, 2.547778)); SearchAround(5, airport, 30); static void SearchAround(int landmarkCount, Landmark referenceLandmark, int distanceInKm) { // Create a reader using var indexDirectory = NCacheDirectory.Open(CacheName, IndexName); using var reader = DirectoryReader.Open(indexDirectory); var searcher = new IndexSearcher(reader); var startingPoint = referenceLandmark.ToPoint(); var context = SpatialContext.GEO; var sortByName = new Sort(new SortField(NameFieldName, SortFieldType.STRING)); // Create a circle of 30km around a reference point var spatialArgs = new SpatialArgs( SpatialOperation.Intersects, context.MakeCircle(startingPoint, DistanceUtils.Dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM))); var strategy = new RecursivePrefixTreeStrategy( new GeohashPrefixTree(context, maxLevels: 11), fieldName: LocationFieldName); // Create a filter using the same strategy var filter = strategy.MakeFilter(spatialArgs); // Search documents var documents = searcher.Search(new MatchAllDocsQuery(), filter, landmarkCount, sortByName); foreach (var scoreDoc in documents.ScoreDocs) { var document = searcher.Doc(scoreDoc.Doc); // Create a result tuple var (name, awayInKm) = document.ToResponse(startingPoint); Console.WriteLine($"Name: {name}"); Console.WriteLine($"Distance: {awayInKm}"); } } |
일부 키워드가 포함된 문서를 검색하는 대신 GeoSpatial 인덱스를 사용하여 해당 위치를 기반으로 검색을 수행합니다.
공항에서 가까운 모든 랜드마크를 찾기 위해 우리는 Search()
메서드, 필터, 개수 및 정렬 순서. 우리는 같은 필터를 만들었습니다. SpatialStrategy
우리가 전에 사용했던. 그리고 우리는 썼다 SpatialArg
킬로미터 단위의 지정된 반경을 가진 시작점을 중심으로 원 안의 모든 문서를 쿼리합니다. 이와 같이,
1 2 3 |
var spatialArgs = new SpatialArgs( SpatialOperation.Intersects, context.MakeCircle(startingPoint, DistanceUtils.Dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM))); |
그런 다음 발견된 각 문서에서 응답 객체를 생성하고 시작점으로부터의 거리를 계산했습니다. 이와 같이,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using Spatial4n.Core.Context; using Spatial4n.Core.Distance; using Spatial4n.Core.Shapes; using System.Globalization; using Document = Lucene.Net.Documents.Document; namespace Landmarks; public static class LocationExtensions { public static (string Name, double DistanceInKm) ToResponse(this Document document, IPoint startingPoint) { var name = document.GetField("name").GetStringValue(); var location = document.GetField("landmarkLocation").GetStringValue(); var positions = location.Split(' '); var x = double.Parse(positions[0], CultureInfo.InvariantCulture); var y = double.Parse(positions[1], CultureInfo.InvariantCulture); var distanceInDeg = SpatialContext.GEO.CalcDistance(startingPoint, x, y); var distanceInKm = distanceInDeg * DistanceUtils.DEG_TO_KM; return (name, distanceInKm); } } |
랜드마크 위치를 구문 분석하고 CalcDistance()
시작점으로 문서 위치를 찾았습니다.
다음은 공항에서 가장 가까운 XNUMX개의 색인화된 랜드마크입니다.
NCache 세부 정보 다운로드 NCache 전체 텍스트 인덱싱 NCache 루센
결론
Distributed Lucene에 대한 GeoSpatial 인덱스를 구현하려면 다음이 필요합니다. SpatialDocument
일반 대신 Document
.
이후 NCache Lucene.NET API를 구현하면 다음을 사용하여 Lucene 코드를 확장할 수 있습니다. NCache 몇 줄의 코드를 변경하고 몇 가지 명명 규칙을 따르면 됩니다.
다른 최근에 대해 알아보려면 NCache 기능, 확인 새로운 기능 NCache? Distributed Lucene이 있는 GeoSpatial 인덱스에 대한 자세한 내용은 다음을 확인하십시오. 분산 Lucene 지리 공간 API.
코드를 따르기 위해 이 게시물에서 작성했습니다. NCache Rescale과 함께 비즈니스를 가속화하는 방법에 대해 알아보세요. GitHub의 저장소.