Consultas de proyección

La mayoría de las consultas de Cloud Datastore muestran entidades completas como resultado. Sin embargo, solo unas pocas propiedades de la entidad son relevantes para las aplicaciones. Las consultas de proyección te permiten hacer consultas en Cloud Datastore solo para aquellas propiedades específicas de una entidad que realmente necesitas, con una latencia y un costo más bajos que si recuperas la entidad completa.

Las consultas de proyección son similares a las consultas de SQL que tienen el siguiente formato:

SELECT name, email, phone FROM CUSTOMER

Puedes usar todas las funciones de filtrado y clasificación disponibles para las consultas de entidades estándar, con las limitaciones que se describen a continuación. La consulta muestra resultados abreviados en los que solo se propagan los valores de las propiedades especificadas (name, email y phone en el ejemplo). Todas las demás propiedades no tienen datos.

Cómo usar consultas de proyección en Java 8

Para crear una consulta de proyección, debes crear un objeto Query y agregarle propiedades con el método addProjection():

Java 8

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

Java 7

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

El tipo que especificas para cada propiedad debe coincidir con el tipo que usaste cuando definiste por primera vez la propiedad con Entity.setProperty(). El ejemplo siguiente muestra cómo procesar los resultados de la consulta mediante la iteración a través de la lista de entidades mostrada y la conversión de cada valor de propiedad al tipo esperado:

Java 8

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Java 7

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Agrupación(experimental)

Las consultas de proyección pueden usar el método setDistinct() para garantizar que solo los resultados únicos por completo se muestren en un conjunto de resultados. Esto solo mostrará el primer resultado para las entidades que tengan los mismos valores para las propiedades que se están proyectando.

Java 8

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

Java 7

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

Limitaciones para las proyecciones

Las consultas de proyección están sujetas a las limitaciones siguientes:

  • Solo se pueden proyectar las propiedades indexadas.

    La proyección no admite propiedades que no están indexadas, ya sea de forma explícita o implícita. No se indexan las strings largas de texto (Text) ni de bytes (Blob).

  • No se puede proyectar la misma propiedad más de una vez.

  • No se pueden proyectar las propiedades mencionadas en un filtro de igualdad (EQUAL) o membresía (IN).

    Por ejemplo,

    SELECT A FROM kind WHERE B = 1
    

    Es una consulta válida, ya que la propiedad proyectada no se usa en el filtro de igualdad. También lo es la siguiente consulta:

    SELECT A FROM kind WHERE A > 1
    

    No es un filtro de igualdad. Sin embargo, la siguiente consulta no es válida:

    SELECT A FROM kind WHERE A = 1
    

    no es válida (ya que la propiedad proyectada se usa en el filtro de igualdad).

  • Los resultados que muestra una consulta de proyección no se deben volver a guardar en Cloud Datastore

    Dado que la consulta muestra resultados que solo están parcialmente propagados, estos no deben volver a escribirse en Cloud Datastore.

Proyecciones y propiedades con valores múltiples

La proyección de una propiedad con valores múltiples no propagará todos los valores para esa propiedad. En su lugar, se mostrará una entidad independiente para cada combinación única de valores proyectados que coincidan con la consulta. Por ejemplo, supón que tienes una entidad del tipo Foo con dos propiedades con valores múltiples, A y B:

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

Luego, la consulta de proyección

SELECT A, B FROM Foo WHERE A < 3

mostrará cuatro entidades con las combinaciones de valores siguientes:

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

Ten en cuenta que, si una entidad tiene una propiedad de valores múltiples sin valores, no se incluirán entradas en el índice y no se mostrarán resultados para esa entidad a partir de una consulta de proyección que incluya esa propiedad.

Índices para proyecciones

Las consultas de proyección requieren que todas las propiedades especificadas en la proyección se incluyan en un índice de Cloud Datastore. El servidor de desarrollo de App Engine genera automáticamente los índices que necesitas en el archivo de configuración de índices, datastore-indexes-auto.xml, que se sube junto con tu aplicación.

Una manera de minimizar el número de índices requeridos es proyectar las mismas propiedades sistemáticamente, incluso cuando no todas sean necesarias siempre. Por ejemplo, estas consultas requieren dos índices independientes:

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

Sin embargo, si siempre proyectas las propiedades A, B y C, incluso si no necesitas C, solo necesitarás un índice.

Convertir una consulta existente en una consulta de proyección puede requerir que se cree un índice nuevo si las propiedades de la proyección no están incluidas en otra parte de la consulta. Por ejemplo, supón que tienes una consulta existente como esta:

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

que requiere el índice

Index(Kind, A, B)

Convertir esto en cualquiera de estas consultas de proyección

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

ingresa una propiedad nueva (C) y, por ello, deberás compilar un índice nuevo Index(Kind, A, B, C). Ten en cuenta que la consulta de proyección

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

no cambiaría el índice requerido, debido a que las propiedades proyectadas A y B ya estaban incluidas en la consulta existente.