Datastore에 데이터 저장


이 Python 방명록 코드 둘러보기는 Datastore에 구조화된 데이터를 저장하는 방법을 보여줍니다. App Engine 및 Datastore를 사용하면 데이터 배포, 복제, 부하 분산에 대해 걱정할 필요가 없습니다. 이 모든 작업이 간단한 API를 통해 자동으로 수행되며 개발자에게 강력한 쿼리 엔진 및 트랜잭션 기능도 제공됩니다.

이 페이지는 여러 페이지로 구성된 가이드의 일부입니다. 처음부터 시작하고 설정 안내를 참조하려면 방명록 만들기로 이동하세요.

제출된 인사말 저장

데이터는 항목이라는 객체의 Datastore에 기록됩니다. 각 항목에는 항목을 고유하게 식별하는 가 있습니다. 항목은 선택적으로 다른 항목을 자신의 상위 요소로 지정할 수 있으며, 첫 번째 항목이 상위 항목의 하위 요소가 됩니다. 따라서 데이터 저장소의 항목은 파일 시스템의 디렉토리 구조와 유사한 계층구조 형식의 공간을 형성합니다. 자세한 내용은 Strong Consistency을 위한 데이터 구조화를 참조하세요.

App Engine에는 Python용 데이터 모델링 API가 포함되어 있습니다. 데이터 모델링 API를 사용하기 위해 샘플 앱은 google.appengine.ext.ndb 모듈을 가져옵니다. 각 인사말에는 작성자 이름, 메시지 내용, 메시지가 게시된 날짜 및 시간이 포함됩니다. 앱은 메시지를 시간순으로 표시합니다. 다음 코드는 데이터 모델을 정의합니다.

class Author(ndb.Model):
    """Sub model for representing an author."""
    identity = ndb.StringProperty(indexed=False)
    email = ndb.StringProperty(indexed=False)

class Greeting(ndb.Model):
    """A main model for representing an individual Guestbook entry."""
    author = ndb.StructuredProperty(Author)
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

이 코드는 세 가지 속성을 가진 Greeting 모델을 정의합니다. author 값은 이메일 주소와 작성자 ID를 포함하는 Author 객체이고, content 값은 문자열, date 값은 datetime.datetime입니다.

일부 속성 생성자는 매개변수를 사용하여 동작을 추가로 구성합니다. ndb.StringProperty 생성자에 indexed=False 매개변수를 전달하면 이 속성 값의 색인이 생성되지 않습니다. 이렇게 하면 앱이 쿼리에서 해당 속성을 사용하지 않기 때문에 불필요한 쓰기 작업이 수행되지 않습니다. 애플리케이션이 다른 값을 제공하지 않는 경우 ndb.DateTimeProperty 생성자에 auto_now_add=True 매개변수를 전달하면 모델이 자동으로 객체가 생성된 시간의 datetime 스탬프를 새 객체에 제공하도록 구성됩니다. 속성 유형 및 해당 옵션의 전체 목록은 NDB 속성을 참조하세요.

애플리케이션은 데이터 모델을 사용하여 새로운 Greeting 객체를 만들고 Datastore에 저장합니다. Guestbook 핸들러는 새 인사말을 만들고 Datastore에 저장합니다.

class Guestbook(webapp2.RequestHandler):

    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each
        # Greeting is in the same entity group. Queries across the
        # single entity group will be consistent. However, the write
        # rate to a single entity group should be limited to
        # ~1/second.
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = Author(
                    identity=users.get_current_user().user_id(),
                    email=users.get_current_user().email())

        greeting.content = self.request.get('content')
        greeting.put()

        query_params = {'guestbook_name': guestbook_name}
        self.redirect('/?' + urllib.urlencode(query_params))

Guestbook 핸들러는 새 Greeting 객체를 만든 다음 사용자가 게시한 데이터를 사용하여 authorcontent 속성을 설정합니다. Greeting의 상위 요소는 Guestbook 항목입니다. Guestbook 항목을 만든 다음 다른 항목의 상위 요소로 설정할 필요가 없습니다. 이 예시에서 상위 요소는 트랜잭션 및 일관성 유지를 위한 자리표시자로 사용됩니다. 자세한 내용은 트랜잭션 페이지를 참조하세요. 공통된 상위 요소를 공유하는 객체는 동일한 항목 그룹에 속합니다. 이 코드는 date 속성을 설정하지 않으므로 dateauto_now_add=True를 사용하여 현재로 자동 설정됩니다.

마지막으로 greeting.put()은 새 객체를 Datastore에 저장합니다. 쿼리에서 이 객체를 가져올 경우 put()을 실행하면 기존 객체가 업데이트됩니다. 이 객체는 모델 생성자를 사용하여 만들었기 때문에 put()을 실행하면 새 객체가 Datastore에 추가됩니다.

Datastore의 쿼리는 항목 그룹 내에서만 strong consistency를 가지므로 이 코드는 각 인사말에 대해 동일한 상위 요소를 설정하여 한 방명록의 모든 인사말을 동일한 항목 그룹에 할당합니다. 즉, 인사말이 작성되면 바로 사용자에게 표시됩니다. 하지만 동일한 항목 그룹에 쓸 수 있는 속도는 초당 항목 그룹에 한 번으로 제한됩니다. 실제 애플리케이션을 설계할 경우 이 사실을 염두에 두어야 합니다. Memcache와 같은 서비스를 사용하면 쓰기 후 항목 그룹 전체를 쿼리할 때 사용자에게 오래된 결과가 표시될 가능성을 줄일 수 있습니다.

제출된 인사말 검색

Datastore에는 데이터 모델을 위한 정교한 쿼리 엔진이 있습니다. Datastore는 전통적인 관계형 데이터베이스가 아니므로 SQL로 쿼리가 지정되지 않습니다. 대신 데이터는 Datastore 쿼리 또는 SQL과 유사한 쿼리 언어인 GQL을 통해 쿼리됩니다. Datastore의 모든 쿼리 기능에 액세스하려면 GQL을 통해 쿼리를 사용하는 것이 좋습니다.

MainPage 핸들러가 이전에 제출된 인사말을 검색하고 표시합니다. 쿼리는 greetings_query.fetch(10) 호출을 통해 수행됩니다.

Datastore 색인 자세히 알아보기

Datastore의 모든 쿼리는 정렬된 속성 값을 항목 키에 매핑하는 테이블인 하나 이상의 색인에서 계산됩니다. App Engine이 애플리케이션의 데이터 저장소 크기와 관계없이 빠르게 결과를 제공할 수 있는 것은 바로 이 때문입니다. 대부분의 쿼리는 기본 제공되는 색인을 통해 계산할 수 있지만 보다 복잡한 쿼리의 경우 Datastore에 커스텀 색인이 필요합니다. 커스텀 색인이 없으면 Datastore에서 이러한 쿼리를 효율적으로 실행할 수 없습니다.

예를 들어 방명록 애플리케이션은 상위 쿼리와 정렬 순서를 사용하여 방명록별로 필터링하고 날짜별로 순서를 지정합니다. 이렇게 하려면 애플리케이션의 index.yaml 파일에 커스텀 색인을 지정해야 합니다. 이 파일을 직접 수정하거나 애플리케이션에서 로컬로 쿼리를 실행하여 자동으로 파일을 관리할 수 있습니다. 색인이 index.yaml에 정의된 후 애플리케이션을 배포하면 커스텀 색인 정보도 배포됩니다.

index.yaml의 쿼리 정의는 다음과 같습니다.

indexes:
- kind: Greeting
  ancestor: yes
  properties:
  - name: date
    direction: desc

Datastore 색인 페이지에서 Datastore 색인과 관련된 모든 정보를 확인할 수 있습니다. index.yaml 파일의 올바른 사양은 Python Datastore 색인 구성을 참조하세요.