Map Search Around 통합
Search Around는 링크나 함수로 관련 객체를 탐색합니다. 조회 한도는 Control Panel에서 구성할 수 있습니다. Tile 표시와의 제약은 로딩 방식을 확인합니다.
직접 링크
지리공간 객체에서 온톨로지 링크로 연결된 다른 지리공간 객체를 탐색할 수 있습니다.
중간 객체를 합친 링크 탐색
지리공간 객체 둘이 중간 객체를 통해 연결되어 있으면 두 단계 탐색을 하나의 관계로 표시할 수 있습니다. 중간 객체에는 지리 정보가 없어도 됩니다.
- Factory와 Supplier 사이의 Supply Contract를 중간 객체로 쓰면 계약을 나타내는 호를 그립니다.
- Customer와 Distribution Center 사이에 Delivery 이벤트가 있으면 호 위를 움직이는 원으로 이벤트를 표시합니다. 위치는 이벤트 시작과 끝 및 현재 선택 시각을 사용하여 호 위에서 보간합니다.
유형 전체에 Link merge 적용
중간 객체 유형의 Capabilities > Search Around에서 Link merge always를 켭니다. 그러면 그 유형 자체는 Search Around 목록에 나타나지 않고 전이 링크가 나타납니다.
예를 들어 Distribution Center와 Customer 사이의 Delivery를 지정하면 Distribution Center에서 Delivery 대신 Customer (via Delivery)를 선택합니다.
특정 탐색 방향만 적용
중간 유형의 Search Around에서 Incoming links to merge와 Outgoing links to merge를 모두 지정합니다.
Supplier에서 Delivery를 거쳐 Distribution Center로 탐색하려면 Delivery 유형의 Incoming에 Delivery <-> Supplier, Outgoing에 Delivery <-> Distribution Center를 설정합니다.
양방향을 제공하려면 두 링크를 Incoming과 Outgoing 양쪽에 모두 구성합니다. 그러면 Supplier의 Distribution Centers (via Delivery)와 Distribution Center의 Suppliers (via Delivery)를 모두 사용할 수 있습니다.
함수 기반 Search Around
TypeScript 함수는 선택한 객체를 받아 필요한 온톨로지 데이터를 탐색하고 결과를 반환합니다.
| 결과 필드 | 지도에서의 동작 |
|---|---|
| objectRids | 객체들을 지도에 추가 |
| edges | 원본 및 대상 객체를 추가하고 그 사이에 호 표시. 선택적인 중간 객체는 호를 선택할 때 목록에 표시 |
| measures | 시계열 measure를 Timeline에 추가 |
정확한 반환형
함수의 선언 반환형은 Promise<IMapSearchAroundResults>여야 합니다. Map은 이름과 구조로 함수를 발견하므로 다음 인터페이스 이름과 필드를 그대로 사용합니다.
export interface IMapSearchAroundResults {
objectRids?: string[];
edges?: IMapSearchAroundEdge[];
measures?: IMapSearchAroundMeasure[];
}
export interface IMapSearchAroundEdge {
sourceObjectRid: string;
targetObjectRid: string;
intermediaryObjectRids?: string[];
}
export interface IMapSearchAroundMeasure {
objectRids: string[];
measureId: string;
}
입력
객체 관련 입력은 정확히 하나여야 합니다.
| 입력 형태 | 메뉴에 나타나는 선택 조건 |
|---|---|
| 객체 하나 | 지정한 유형의 객체 하나가 선택됨 |
| 해당 객체의 배열 | 지정한 유형의 객체가 선택됨 |
ObjectSet<객체 유형> | 지정한 유형의 객체가 선택됨 |
추가 스칼라 인수는 여러 개 둘 수 있습니다. 지원형은 string, boolean, Integer, Long, Float, Double, LocalDate와 Timestamp입니다. 추가 입력이 있는 함수를 실행하면 사용자에게 값을 묻습니다.
공항 탐색 함수 세 가지
다음 TypeScript v1 예시는 생성 API에 ExampleDataAirport와 ExampleDataRoute가 있고, 아래 바인딩이 정의된 구성을 전제로 합니다.
- 공항의 airportLocation은 위치이며 airport는 공항 코드입니다.
- 공항 집합은 searchAroundExampleDataRunway와 searchAroundRoutes 링크 탐색을 제공합니다.
- 노선은 origin과 dest에 출발 및 도착 공항 코드를 가집니다.
- 선택한 공항들의 코드는 비어 있지 않고 고유해야 합니다.
앞의 반환 인터페이스들과 아래 구현을 같은 파일에 둡니다.
import { Distance, Filters, Function, Integer, UserFacingError } from "@foundry/functions-api";
import { ExampleDataAirport, ObjectSet, Objects } from "@foundry/ontology-api";
export class MapSearchAroundFunctions {
private requireRid(rid: string | null | undefined): string {
if (rid == null) {
throw new UserFacingError("객체 RID를 확인할 수 없습니다.");
}
return rid;
}
@Function()
public async airportsRelatedObjects(
airportSet: ObjectSet<ExampleDataAirport>,
): Promise<IMapSearchAroundResults> {
const [runways, routes] = await Promise.all([
airportSet.searchAroundExampleDataRunway().allAsync(),
airportSet.searchAroundRoutes().allAsync(),
]);
const objectRids: string[] = [];
for (const runway of runways) {
objectRids.push(this.requireRid(runway.rid));
}
for (const route of routes) {
objectRids.push(this.requireRid(route.rid));
}
return { objectRids };
}
@Function()
public async nearbyAirports(
airport: ExampleDataAirport,
distanceKm?: Integer,
): Promise<IMapSearchAroundResults> {
const point = airport.airportLocation;
if (point === undefined) {
throw new UserFacingError("주변 검색에 사용할 공항 위치가 없습니다.");
}
const distance = Distance.ofKilometers(distanceKm ?? 50);
const nearby = await Objects.search().exampleDataAirport()
.filter(candidate => candidate.airportLocation.withinDistanceOf(point, distance))
.allAsync();
const objectRids: string[] = [];
for (const candidate of nearby) {
objectRids.push(this.requireRid(candidate.rid));
}
return { objectRids };
}
@Function()
public async routesBetweenAirports(
airportSet: ObjectSet<ExampleDataAirport>,
): Promise<IMapSearchAroundResults> {
const airports = await airportSet.allAsync();
if (airports.length === 0) {
return { edges: [] };
}
const airportCodes: string[] = [];
const airportRidsByCode = new Map<string, string>();
for (const airport of airports) {
const code = airport.airport;
if (code == null || code.length === 0 || airportRidsByCode.has(code)) {
throw new UserFacingError("선택한 공항 코드는 비어 있지 않고 고유해야 합니다.");
}
airportCodes.push(code);
airportRidsByCode.set(code, this.requireRid(airport.rid));
}
const routes = await Objects.search().exampleDataRoute()
.filter(route => Filters.and(
route.origin.exactMatch(...airportCodes),
route.dest.exactMatch(...airportCodes),
))
.allAsync();
const edges: IMapSearchAroundEdge[] = [];
for (const route of routes) {
const source = route.origin == null ? undefined : airportRidsByCode.get(route.origin);
const target = route.dest == null ? undefined : airportRidsByCode.get(route.dest);
if (source === undefined || target === undefined) {
throw new UserFacingError("노선의 출발 및 도착 공항을 확인할 수 없습니다.");
}
edges.push({
sourceObjectRid: source,
targetObjectRid: target,
intermediaryObjectRids: [this.requireRid(route.rid)],
});
}
return { edges };
}
}
| 함수 | 결과 |
|---|---|
| airportsRelatedObjects | 선택한 공항들의 활주로와 노선 객체 |
| nearbyAirports | 지정 거리 안의 공항. 거리를 생략하면 50 km이며 기준 공항 자체도 거리 조건에 포함될 수 있음 |
| routesBetweenAirports | 출발과 도착이 모두 선택한 공항 집합 안에 있는 노선. 노선 객체를 각 호의 중간 객체로 제공 |
위치나 식별자를 확인할 수 없는 입력은 오류로 알립니다. 선택 집합이 실제로 비어 있으면 연결 노선도 빈 배열입니다.
게시와 접근 조건
객체 조회에는 가능한 한 비동기 allAsync와 getAsync를 사용하고 독립적인 조회를 함께 실행합니다. 생성된 링크 바인딩 이름은 실제 저장소에서 가져온 이름과 맞춰야 합니다.
Map은 가장 최근에 게시한 함수 버전을 사용합니다. 게시할 브랜치 또는 커밋에 1.0.0 같은 semver 호환 태그를 지정합니다.
저장소 Settings의 Ontology에 사용할 객체 유형과 링크 접근이 구성되어 있어야 합니다. 객체 유형과 기반 데이터셋이 다른 프로젝트에 있다면 저장소 프로젝트에 해당 유형과 데이터셋의 참조가 필요합니다.