Datastore 쿼리

Datastore 쿼리는 지정한 조건 조합에 맞는 항목을 Cloud Datastore에서 검색합니다.

일반적인 쿼리에는 다음이 포함됩니다.

  • 쿼리가 적용되는 항목 종류
  • 항목의 속성 값, 키, 상위 항목을 기준으로 하는 필터(선택사항)
  • 결과를 순차적으로 배열할 정렬 순서(선택사항)
쿼리가 실행되면 지정한 모든 필터를 만족하는 지정한 종류의 모든 항목이 지정한 정렬 순서대로 검색됩니다. 쿼리는 읽기 전용으로 실행됩니다.

이 페이지에서는 App Engine에서 Cloud Datastore로부터 데이터를 검색하는 데 사용되는 쿼리의 구조와 종류를 설명합니다.

필터

쿼리 필터는 검색할 항목의 속성, , 상위 항목에 대한 제약 조건을 설정합니다.

속성 필터

속성 필터는 다음을 지정합니다.

  • 속성 이름
  • 비교 연산자
  • 속성 값
예를 들면 다음과 같습니다.

속성 값은 애플리케이션에서 제공해야 합니다. 속성 값은 다른 속성을 참조하거나 그와 관련하여 계산될 수 없습니다. 비교 연산자로 설명된 방식에 따라 필터에 지정된 값과 해당 값이 비교되는 지정된 이름의 속성이 있으면 항목이 필터를 만족합니다.

비교 연산자는 다음 중 하나일 수 있으며 중첩 클래스 Query.FilterOperator의 열거형 상수로 정의됩니다.

연산자 의미
EQUAL 같음
LESS_THAN 미만
LESS_THAN_OR_EQUAL 이하
GREATER_THAN 초과
GREATER_THAN_OR_EQUAL 이상
NOT_EQUAL 같지 않음
IN 구성원 관계(지정된 목록의 값 중 하나라도 일치)

NOT_EQUAL 연산자는 실제로는 두 개의 쿼리를 수행합니다. 다른 모든 필터를 그대로 두고 NOT_EQUAL 필터를 LESS_THAN 필터로 바꾸는 쿼리 하나와 GREATER_THAN 필터로 바꾸는 쿼리 하나입니다. 그런 다음 결과를 순서대로 병합합니다. 쿼리는 NOT_EQUAL 필터를 하나만 가질 수 있으며, 이 필터를 갖는 쿼리는 다른 불일치 필터를 가질 수 없습니다.

IN 연산자도 여러 쿼리를 수행합니다. 지정된 목록의 항목마다 쿼리가 한 번씩 실행되며, 다른 모든 필터를 그대로 두고 IN 필터를 EQUAL 필터로 바꿉니다. 그런 다음 목록의 항목 순서대로 결과를 병합합니다. 하나의 쿼리에 IN 필터가 두 개 이상이면 IN 목록의 가능한 값 조합마다 하나씩 여러 개의 쿼리로 수행됩니다.

NOT_EQUAL 또는 IN 연산자를 포함하는 단일 쿼리의 하위 쿼리는 최대 30개로 제한됩니다.

JDO/JPA 프레임워크에서 NOT_EQUALIN 쿼리가 여러 쿼리로 변환되는 방법에 대한 자세한 내용은 Queries with != 및 IN 필터를 사용하는 쿼리를 참조하세요.

키 필터

항목 키의 값을 필터링하려면 특수 속성 Entity.KEY_RESERVED_PROPERTY를 사용합니다.

자바 8

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query("Person").setFilter(keyFilter);

자바 7

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query("Person").setFilter(keyFilter);

Entity.KEY_RESERVED_PROPERTY에 대한 오름차순 정렬도 지원됩니다.

불일치 비교 시 다음 순서의 기준에 따라 키가 정렬됩니다.

  1. 상위 경로
  2. 항목 종류
  3. 식별자(키 이름 또는 숫자 ID)

마찬가지로 상위 경로의 요소도 종류(문자열)에 이어 키 이름 또는 숫자 ID로 비교됩니다. 종류와 키 이름은 문자열이며 바이트 값으로 정렬되고, 숫자 ID는 정수이며 숫자로 정렬됩니다. 상위 항목 및 종류가 동일한 항목에 키 이름 문자열과 숫자 ID가 함께 사용되면 숫자 ID를 가진 항목이 키 이름을 가진 항목보다 앞에 옵니다.

키를 대상으로 하는 쿼리는 속성을 대상으로 하는 쿼리와 마찬가지로 색인을 사용하며 커스텀 색인이 필요합니다. 단, 예외적으로 키에 대한 불일치 필터 또는 오름차순 정렬 순서에는 커스텀 색인이 필요하지 않지만 키에 대한 내림차순 정렬 순서에는 커스텀 색인이 필요합니다. 모든 쿼리와 마찬가지로, 커스텀 색인이 필요한 쿼리를 테스트하면 개발용 웹 서버에서 색인 구성 파일에 적절한 항목을 만듭니다.

상위 항목 필터

지정한 상위 항목으로 Datastore 쿼리를 필터링하여 반환되는 결과에 해당 상위 항목의 하위 항목만 포함할 수 있습니다.

자바 8

Query q = new Query("Person").setAncestor(ancestorKey);

자바 7

Query q = new Query("Person").setAncestor(ancestorKey);

특수 쿼리 유형

특정 유형의 쿼리는 다음과 같습니다.

비구분 쿼리

종류 및 상위 항목 필터가 없는 쿼리는 Datastore에서 애플리케이션의 모든 항목을 검색합니다. 여기에는 다른 App Engine 기능에서 생성되고 관리되는 통계 항목, Blobstore 메타데이터 항목 등의 항목(있는 경우)이 포함됩니다. 이 비구분 쿼리는 속성 값에 대한 필터나 정렬 순서를 포함할 수 없습니다. 하지만 Entity.KEY_RESERVED_PROPERTY를 속성 이름으로 지정하여 항목 키를 기준으로 필터링할 수는 있습니다.

자바 8

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setFilter(keyFilter);

자바 7

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setFilter(keyFilter);

상위 쿼리

상위 항목 필터를 갖는 쿼리는 지정한 항목과 하위 항목으로 결과를 제한합니다.

자바 8

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity babyPhoto = new Entity("Photo", tomKey);
babyPhoto.setProperty("imageURL", "http://domain.com/some/path/to/baby_photo.jpg");

Entity dancePhoto = new Entity("Photo", tomKey);
dancePhoto.setProperty("imageURL", "http://domain.com/some/path/to/dance_photo.jpg");

Entity campingPhoto = new Entity("Photo");
campingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/camping_photo.jpg");

List<Entity> photoList = Arrays.asList(weddingPhoto, babyPhoto, dancePhoto, campingPhoto);
datastore.put(photoList);

Query photoQuery = new Query("Photo").setAncestor(tomKey);

// This returns weddingPhoto, babyPhoto, and dancePhoto,
// but not campingPhoto, because tom is not an ancestor
List<Entity> results =
    datastore.prepare(photoQuery).asList(FetchOptions.Builder.withDefaults());

자바 7

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity babyPhoto = new Entity("Photo", tomKey);
babyPhoto.setProperty("imageURL", "http://domain.com/some/path/to/baby_photo.jpg");

Entity dancePhoto = new Entity("Photo", tomKey);
dancePhoto.setProperty("imageURL", "http://domain.com/some/path/to/dance_photo.jpg");

Entity campingPhoto = new Entity("Photo");
campingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/camping_photo.jpg");

List<Entity> photoList = Arrays.asList(weddingPhoto, babyPhoto, dancePhoto, campingPhoto);
datastore.put(photoList);

Query photoQuery = new Query("Photo").setAncestor(tomKey);

// This returns weddingPhoto, babyPhoto, and dancePhoto,
// but not campingPhoto, because tom is not an ancestor
List<Entity> results =
    datastore.prepare(photoQuery).asList(FetchOptions.Builder.withDefaults());

비구분 상위 쿼리

상위 항목 필터를 포함하는 비구분 쿼리는 지정한 상위 항목과 모든 하위 항목을 종류 구분 없이 검색합니다. 이러한 유형의 쿼리에는 커스텀 색인이 필요하지 않습니다. 모든 비구분 쿼리와 마찬가지로 속성 값에 대한 필터 또는 정렬 순서를 포함할 수 없지만 항목의 키를 기준으로 필터링할 수는 있습니다.

자바 8

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setAncestor(ancestorKey).setFilter(keyFilter);

자바 7

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setAncestor(ancestorKey).setFilter(keyFilter);

다음 예에서는 특정 상위 항목의 모든 하위 항목을 검색하는 방법을 보여줍니다.

자바 8

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity weddingVideo = new Entity("Video", tomKey);
weddingVideo.setProperty("videoURL", "http://domain.com/some/path/to/wedding_video.avi");

List<Entity> mediaList = Arrays.asList(weddingPhoto, weddingVideo);
datastore.put(mediaList);

// By default, ancestor queries include the specified ancestor itself.
// The following filter excludes the ancestor from the query results.
Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, tomKey);

Query mediaQuery = new Query().setAncestor(tomKey).setFilter(keyFilter);

// Returns both weddingPhoto and weddingVideo,
// even though they are of different entity kinds
List<Entity> results =
    datastore.prepare(mediaQuery).asList(FetchOptions.Builder.withDefaults());

자바 7

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity weddingVideo = new Entity("Video", tomKey);
weddingVideo.setProperty("videoURL", "http://domain.com/some/path/to/wedding_video.avi");

List<Entity> mediaList = Arrays.asList(weddingPhoto, weddingVideo);
datastore.put(mediaList);

// By default, ancestor queries include the specified ancestor itself.
// The following filter excludes the ancestor from the query results.
Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, tomKey);

Query mediaQuery = new Query().setAncestor(tomKey).setFilter(keyFilter);

// Returns both weddingPhoto and weddingVideo,
// even though they are of different entity kinds
List<Entity> results =
    datastore.prepare(mediaQuery).asList(FetchOptions.Builder.withDefaults());

키 전용 쿼리

키 전용 쿼리는 항목 자체가 아니라 결과 항목의 키만 반환하므로, 전체 항목을 검색할 때보다 지연 시간과 비용이 낮습니다.

실제로 필요한 것보다 많은 항목을 가져올 수 있는 일반 쿼리를 실행하는 대신 키 전용 쿼리를 먼저 실행한 후 결과에서 항목의 하위 집합을 가져오는 것이 더 경제적인 경우가 종종 있습니다.

프로젝션 쿼리

쿼리 결과 중에 몇 가지 특정 속성의 값만 실제로 필요한 경우가 있습니다. 이러한 경우 프로젝션 쿼리를 사용하면 실제로 필요한 속성만 검색하여 전체 항목을 검색할 때보다 지연 시간과 비용을 낮출 수 있습니다. 자세한 내용은 프로젝션 쿼리 페이지를 참조하세요.

정렬 순서

쿼리 정렬 순서는 다음을 지정합니다.

  • 속성 이름
  • 정렬 방향(오름차순 또는 내림차순)

예를 들면 다음과 같습니다.

쿼리에 정렬 순서가 여러 개 있으면 지정한 순서대로 적용됩니다. 다음 예에서는 성에 따라 오름차순으로 정렬한 후 키에 따라 내림차순으로 정렬합니다.

정렬 순서가 지정되지 않으면 결과는 Cloud Datastore에서 검색한 순서대로 반환됩니다.

참고: Cloud Datastore에서 쿼리를 실행하는 방식으로 인해, 쿼리에서 속성에 대한 불일치 필터를 지정하고 다른 속성에 대한 정렬 순서를 지정하는 경우 불일치 필터에 사용되는 속성이 다른 속성보다 먼저 정렬되어야 합니다.

색인

모든 Datastore 쿼리는 색인의 속성에 지정된 순서대로 항목 키와 항목의 상위(선택 사항)를 포함하는 하나 이상의 색인을 사용하여 결과를 계산합니다. 색인은 애플리케이션이 해당 항목을 대상으로 수행하는 모든 변경 내용을 반영하도록 증분 방식으로 업데이트되므로 추가 계산하지 않아도 모든 쿼리의 결과가 올바르게 제공됩니다.

App Engine은 항목의 각 속성에 대해 간단한 색인을 미리 정의합니다. App Engine 애플리케이션은 datastore-indexes.xml이라는 색인 구성 파일에 커스텀 색인을 추가로 정의할 수 있으며, 이 파일은 애플리케이션의 /war/WEB-INF/appengine-generated 디렉토리에 생성됩니다. 개발 서버는 기존 색인으로 실행할 수 없는 쿼리를 접할 때 이 파일에 자동으로 제안 항목을 추가합니다. 애플리케이션을 업로드하기 전에 이 파일을 수정하여 색인을 직접 조정할 수 있습니다.

쿼리 인터페이스 예

저수준 자바 Datastore API는 쿼리를 생성하는 Query 클래스 및 Datastore에서 항목을 검색하는 PreparedQuery 인터페이스를 제공합니다.

자바 8

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

// Use CompositeFilter to combine multiple filters
CompositeFilter heightRangeFilter =
    CompositeFilterOperator.and(heightMinFilter, heightMaxFilter);

// Use class Query to assemble a query
Query q = new Query("Person").setFilter(heightRangeFilter);

// Use PreparedQuery interface to retrieve results
PreparedQuery pq = datastore.prepare(q);

for (Entity result : pq.asIterable()) {
  String firstName = (String) result.getProperty("firstName");
  String lastName = (String) result.getProperty("lastName");
  Long height = (Long) result.getProperty("height");

  out.println(firstName + " " + lastName + ", " + height + " inches tall");
}

자바 7

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

// Use CompositeFilter to combine multiple filters
CompositeFilter heightRangeFilter =
    CompositeFilterOperator.and(heightMinFilter, heightMaxFilter);

// Use class Query to assemble a query
Query q = new Query("Person").setFilter(heightRangeFilter);

// Use PreparedQuery interface to retrieve results
PreparedQuery pq = datastore.prepare(q);

for (Entity result : pq.asIterable()) {
  String firstName = (String) result.getProperty("firstName");
  String lastName = (String) result.getProperty("lastName");
  Long height = (Long) result.getProperty("height");

  out.println(firstName + " " + lastName + ", " + height + " inches tall");
}

여기에서는 FilterPredicateCompositeFilter를 사용하여 필터를 생성합니다. 쿼리에 필터를 하나만 설정하는 경우 FilterPredicate만 사용해도 됩니다.

자바 8

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

Query q = new Query("Person").setFilter(heightMinFilter);

자바 7

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

Query q = new Query("Person").setFilter(heightMinFilter);

그러나 쿼리에 필터를 두 개 이상 설정하려는 경우에는 최소한 두 개 이상의 필터가 필요한 CompositeFilter를 사용해야 합니다. 위의 예에서는 단축 도우미 CompositeFilterOperator.and를 사용하며, 다음 예에서는 복합 OR 필터를 생성하는 방법 중 하나를 보여줍니다.

자바 8

Filter tooShortFilter = new FilterPredicate("height", FilterOperator.LESS_THAN, minHeight);

Filter tooTallFilter = new FilterPredicate("height", FilterOperator.GREATER_THAN, maxHeight);

Filter heightOutOfRangeFilter = CompositeFilterOperator.or(tooShortFilter, tooTallFilter);

Query q = new Query("Person").setFilter(heightOutOfRangeFilter);

자바 7

Filter tooShortFilter = new FilterPredicate("height", FilterOperator.LESS_THAN, minHeight);

Filter tooTallFilter = new FilterPredicate("height", FilterOperator.GREATER_THAN, maxHeight);

Filter heightOutOfRangeFilter = CompositeFilterOperator.or(tooShortFilter, tooTallFilter);

Query q = new Query("Person").setFilter(heightOutOfRangeFilter);

다음 단계

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...

App Engine standard environment for Java