Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Java OSDK 참조

Java OSDK는 온톨로지에서 생성한 객체, 액션과 쿼리를 Java 코드에서 사용합니다. Developer Console에서 앱이 사용할 리소스를 선택하고 생성한 Maven 패키지를 설치해야 합니다. Java 지원 버전은 17부터 21입니다.

아래 호출 예제의 client는 자신의 생성 패키지에서 만든 인증된 FoundryClient입니다. 생성 객체와 Filter, Ordering, 액션 요청 및 응답 클래스를 해당 패키지에서 가져오며, 공통 FetchRequest와 집계 타입은 생성 SDK가 제공한 import 안내를 따릅니다. 예제 블록은 이 타입과 client가 있는 앱 메서드 본문에서 사용합니다.

예제 Restaurant

표시 이름API 이름자료형
Restaurant Id, 기본 키restaurantIdString
Restaurant Name, 제목restaurantNameString
AddressaddressString
E MaileMailString
Number Of ReviewsnumberOfReviewsInteger
Phone NumberphoneNumberString
Review SummaryreviewSummaryString
Date Of OpeningdateOfOpeningLocalDate

Restaurant은 가상 예제 유형입니다. primaryKey와 restaurantId 변수에는 해당 앱이 선택한 실제 String 키를 전달합니다.

단일 객체와 스트림

fetch는 기본 키에 해당하는 객체의 Optional을 반환합니다. 존재하지 않는 경우 오류로 다루려면 orElseThrow를 사용합니다.

Restaurant restaurant = client.ontology().objects().Restaurant()
    .fetch(primaryKey)
    .orElseThrow(() -> new IllegalArgumentException("식당 객체가 없습니다."));

fetchStream은 소비하는 만큼 다음 페이지를 읽는 Stream<Restaurant>입니다. 전체 목록이 필요하면 toList를 호출하며 그만큼 메모리를 사용합니다.

try (java.util.stream.Stream<Restaurant> restaurants =
        client.ontology().objects().Restaurant().fetchStream()) {
    long count = restaurants.count();
    System.out.println(count);
}

이 코드는 개별 객체를 스트림으로 읽어 셉니다. 개수만 필요한 업무는 아래의 백엔드 count 집계를 사용하면 객체 로드를 줄일 수 있습니다.

java.util.List<Restaurant> allRestaurants;
try (java.util.stream.Stream<Restaurant> restaurants =
        client.ontology().objects().Restaurant().fetchStream()) {
    allRestaurants = restaurants.toList();
}

OSv1(Phonograph)의 객체 로드는 총 10,000개를 넘으면 ObjectsExceededLimit 오류가 발생합니다. OSv2에는 이 총 결과 개수 제한이 없지만 전체 목록의 메모리와 실행 비용은 남습니다.

FetchRequest와 페이지 옵션

설정지원 메서드기본값과 의미
FetchRequest.includeRidsfetch, fetchStreamfalse. 객체 RID 포함
FetchRequest.loadPropertySecurityMetadatafetch, fetchStreamfalse. 속성 보안 메타데이터 포함
FetchRequest.includeAllBaseObjectProperties인터페이스 fetchStream기반 구체 유형의 속성 포함. 객체 유형 조회에는 효과 없음
FetchPageRequest.pageSizefetchPage기본 1,000개
FetchPageRequest.pageTokenfetchPage이전 Page의 다음 토큰
FetchPageRequest.includeRidsfetchPage기본 false
FetchPageRequest.loadPropertySecurityMetadatafetchPage기본 false

RID와 보안 메타데이터를 함께 읽는 요청입니다.

FetchRequest<Restaurant.ObjectProperty> request =
    FetchRequest.<Restaurant.ObjectProperty>builder()
        .includeRids(true)
        .loadPropertySecurityMetadata(true)
        .build();
Restaurant restaurant = client.ontology().objects().Restaurant()
    .fetch(primaryKey, request).orElseThrow();

FetchRequest에 selectedProperties 필드가 있어도 현재 생성 Java 읽기 메서드는 요청에 적용하지 않습니다. 속성 단위 선택을 지원한다고 가정해서는 안 됩니다.

정렬

생성된 RestaurantOrdering의 PROPERTY_NAME_ASC 또는 PROPERTY_NAME_DESC를 orderBy에 전달합니다. 여러 orderBy를 이어 여러 속성으로 정렬할 수 있습니다.

try (java.util.stream.Stream<Restaurant> restaurants = client.ontology().objects().Restaurant()
        .orderBy(RestaurantOrdering.RESTAURANT_NAME_ASC).fetchStream()) {
    java.util.List<Restaurant> ordered = restaurants.toList();
    System.out.println(ordered.size());
}

문자열 정렬은 숫자, 대문자, 소문자 순서로 대소문자를 구분합니다. Cat은 bat보다 먼저입니다.

필터

where에는 생성 RestaurantFilter가 만든 조건을 전달합니다. 결과는 RestaurantObjectSet이며 아직 전체 객체를 로드하지 않습니다.

RestaurantObjectSet named = client.ontology().objects().Restaurant()
    .where(RestaurantFilter.restaurantName().isNull(false));
메서드대상과 의미
startsWith("foo")String의 대소문자 비구분 접두사. foobar는 일치하고 barfoo는 불일치
containsAnyTerm("foo bar")토큰 하나 이상, 순서 무관 및 대소문자 비구분. bar baz에 일치
containsAllTerms("foo bar")모든 토큰, 순서 무관 및 대소문자 비구분. hello foo baz bar에 일치
containsAllTermsInOrder("foo bar")모든 토큰이 같은 순서로 인접. hello foo bar baz에 일치
lt, lte, gt, gte숫자, String과 날짜/시각 비교
eqBoolean, 숫자, String과 날짜/시각 일치
isNull(true)값이 없음
isNull(false)값이 있음
RestaurantFilter.$not조건 부정
RestaurantFilter.$and모든 조건 만족
RestaurantFilter.$or조건 중 하나 이상 만족

Null 조건은 배열을 포함한 해당 속성 타입에 사용할 수 있습니다. 조건을 결합할 때 Java의 && 또는 ||가 아니라 생성 필터의 $and/$or를 사용합니다.

RestaurantObjectSet matches = client.ontology().objects().Restaurant().where(
    RestaurantFilter.$and(
        RestaurantFilter.restaurantName().isNull(false),
        RestaurantFilter.restaurantName().startsWith("foo")
    )
);

집계 지표

집계는 원격 객체 집합에서 계산하므로 전체 객체를 앱 메모리로 읽을 필요가 없습니다. where로 범위를 좁히고 지표 또는 그룹을 지정한 뒤 compute를 호출합니다.

메서드의미
count객체 수. 기본 지표 이름 count
approximateDistinct속성의 고유 값 개수 근사치. 기본 이름 distinctCount
avg숫자 속성 평균
max, min숫자 속성의 최댓값과 최솟값
sum숫자 속성 합

숫자 지표에는 NumericProperty를 사용합니다. 직접 호출한 단일 지표와 이름 있는 집계 반환을 구분합니다.

Double count = client.ontology().objects().Restaurant().count().compute();
Double distinctNames = client.ontology().objects().Restaurant()
    .approximateDistinct(Restaurant.Property.restaurantName()).compute();
Double averageReviews = client.ontology().objects().Restaurant()
    .avg(Restaurant.Property.numberOfReviews()).compute();

이름을 지정한 복수 집계는 Map을 aggregate에 넣으며 AggregationResponse를 반환합니다.

AggregationResponse metrics = client.ontology().objects().Restaurant()
    .aggregate(java.util.Map.of(
        "metricName", Aggregation.approximateDistinct(Restaurant.Property.restaurantName()),
        "avgReview", Aggregation.avg(Restaurant.Property.numberOfReviews())
    ))
    .compute();

원격 응답의 data에는 각 그룹과 metrics의 이름 및 값이 있습니다. 단일 Double 값을 이 HTTP 응답 포장과 혼동하지 않습니다. 고카디널리티 집계의 정확도 및 제외 항목과 반환 그룹 한도를 확인해야 하며 객체 로드 10,000개 제한을 집계 입력 전체의 한도로 해석하지 않습니다.

그룹화

정확한 값과 고정 너비

GroupBy.exact는 속성의 값별 그룹을 만듭니다. maxGroupCount는 생성할 최대 그룹 수입니다. GroupBy.fixedWidth는 숫자 속성을 지정 너비로 나눕니다.

AggregationResponse byName = client.ontology().objects().Restaurant()
    .groupBy(GroupBy.exact(Restaurant.Property.restaurantName()))
    .count().compute();

AggregationResponse byReviewCount = client.ontology().objects().Restaurant()
    .groupBy(GroupBy.fixedWidth(Restaurant.Property.numberOfReviews(), 10))
    .count().compute();

명시적 범위

범위 그룹에는 숫자, Date 또는 Timestamp 속성을 사용하며 시작을 포함하고 끝을 제외합니다.

AggregationResponse ranges = client.ontology().objects().Restaurant()
    .groupBy(GroupBy.range(
        Restaurant.Property.numberOfReviews(),
        java.util.List.of(AggregationRange.of(0, 3), AggregationRange.of(3, 5))
    ))
    .count().compute();

이 예제의 범위는 [0, 3)과 [3, 5)입니다. 그룹 응답에는 startValue와 endValue가 들어갑니다.

날짜와 시각

GroupBy는 속성이 허용하는 단위의 bySeconds, byMinutes, byHours, byDays, byWeeks, byMonths, byQuarters와 byYears를 제공합니다. 단위 수로 버킷 크기를 정합니다.

AggregationResponse byOpeningDate = client.ontology().objects().Restaurant()
    .groupBy(GroupBy.byDays(Restaurant.Property.dateOfOpening(), 10))
    .count().compute();

이 예제는 개업 날짜를 10일 구간으로 나눕니다.

액션 실행

가상의 addReview는 String restaurantId, Integer reviewRating과 String reviewSummary를 받습니다. 실제 실행하면 온톨로지에 변경을 적용합니다.

AddReviewActionResponse response = client.ontology().actions().addReview().apply(
    AddReviewActionRequest.builder()
        .restaurantId(restaurantId)
        .reviewRating(5)
        .reviewSummary("It was great!")
        .build(),
    ReturnEditsMode.ALL
);
boolean valid = response.getValidationResult().accept(new ActionValidationVisitor<Boolean>() {
    @Override
    public Boolean valid(ActionValidationResponse validation) {
        return true;
    }

    @Override
    public Boolean invalid(ActionValidationResponse validation) {
        return false;
    }
});
if (!valid) throw new IllegalStateException("리뷰 액션 제출 조건을 충족하지 못했습니다.");

평점 5와 문구는 가상 입력입니다. visitor는 반환 결과의 valid 또는 invalid 분기를 처리합니다. ReturnEditsMode.ALL은 편집 결과를 반환하도록 지정합니다.

배치 액션과 편집 종류

applyBatch에는 요청 목록을 전달합니다. 응답은 검증 목록 없이 편집 결과를 포함하며, 배치 안의 액션 하나가 실패하면 해당 온톨로지 편집은 모두 적용하지 않습니다.

AddReviewBatchActionResponse response = client.ontology().actions().addReview().applyBatch(
    java.util.List.of(
        AddReviewActionRequest.builder().restaurantId(restaurantId1)
            .reviewRating(5).reviewSummary("It was great!").build(),
        AddReviewActionRequest.builder().restaurantId(restaurantId2)
            .reviewRating(4).reviewSummary("Good food but service can improve.").build()
    ),
    ReturnEditsMode.ALL
);
String editKind = response.getActionEdits().orElseThrow().accept(new ActionEditsVisitor<String>() {
    @Override
    public String objectEdits(ObjectEdits edits) {
        return "objectEdits";
    }

    @Override
    public String largeScaleObjectEdits(ObjectTypeEdits edits) {
        return "largeScaleObjectEdits";
    }
});

위 visitor는 두 편집 결과 종류를 구분합니다. 대규모 결과는 객체 유형 수준이며 개별 수정 객체의 전체 데이터를 모두 반환한다는 의미는 아닙니다. 외부 효과의 원자성은 액션 일관성을 따릅니다.

쿼리 함수 호출

앱에 함수를 추가하여 생성한 쿼리에서 execute와 getReturnValue를 호출합니다. 가상의 findSimilarRestaurants가 String 식당 키를 받아 RestaurantObjectSet을 반환하는 경우입니다.

RestaurantObjectSet similar = client.ontology().queries().findSimilarRestaurants()
    .execute(restaurantId)
    .getReturnValue();

반환 집합에서 필요한 필터나 로드를 이어갑니다.

미디어 참조 속성

가상의 Restaurant.restaurantMenu는 미디어 참조 속성입니다. Media는 내부 MediaReferenceId, 메타데이터와 내용 스트림을 제공합니다.

메서드반환
getId()MediaReferenceId
fetchMetadata()MediaMetadata
openStream()호출자가 닫아야 하는 InputStream

객체와 미디어 값이 없을 때를 구분하여 읽습니다.

Restaurant restaurant = client.ontology().objects().Restaurant().fetch(primaryKey).orElseThrow();
Media menu = restaurant.restaurantMenu().orElseThrow();
MediaMetadata metadata = menu.fetchMetadata();

내용은 스트림을 열어 소비한 뒤 닫습니다. 다음 targetPath는 앱이 정한 로컬 출력 경로이며 기존 파일이 있으면 덮어씁니다.

try (java.io.InputStream input = menu.openStream();
     java.io.OutputStream output = java.nio.file.Files.newOutputStream(targetPath)) {
    input.transferTo(output);
}

호출한 메서드는 IOException을 선언하거나 처리해야 합니다. 작은 파일의 바이트 배열이 필요하면 readAllBytes를 사용할 수 있지만 전체 내용을 메모리에 올립니다.

미디어 업로드와 객체 연결

객체 집합의 uploadRestaurantMenu는 해당 속성이 사용하는 기반 미디어 집합으로 업로드합니다. UploadMediaRequest에는 다음 실제 값을 제공합니다.

  • mediaItemPath: 미디어 집합에서 사용할 파일 경로
  • mediaType: 업로드할 파일의 MIME 유형
  • inputStream: 파일 내용을 제공하는 입력 스트림

request는 이 계약으로 생성한 UploadMediaRequest입니다. 생성 SDK의 builder 타입에 맞춰 파일 스트림을 전달하고 수명을 관리합니다.

Media uploaded = client.ontology().objects().Restaurant().uploadRestaurantMenu(request);

업로드한 Media를 객체에 연결하려면 해당 속성을 바꾸는 액션이 필요합니다. 아래는 가상의 ChangeMenu 액션에서 대상 키 setter가 restaurantId, 미디어 매개변수 setter가 restaurant_menu인 생성 바인딩입니다. 실제 생성 메서드 이름을 확인하여 사용합니다.

client.ontology().actions().changeMenuAction().apply(
    ChangeMenuActionRequest.builder()
        .restaurantId(restaurantId)
        .restaurant_menu(uploaded)
        .build()
);

다른 객체의 기존 메뉴를 연결할 때는 uploaded 대신 그 객체의 restaurantMenu().orElseThrow()를 전달합니다. 미디어 참조는 같은 미디어 집합을 가리켜야 합니다. 집합 A에 업로드한 항목을 집합 B의 미디어 속성으로 그대로 연결할 수 없습니다.

다른 언어의 생성 SDK에는 다른 타입과 기능 범위가 있으므로 TypeScript 참조 및 Python 참조를 각각 확인합니다.