Google Code disponible en: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
Cada consulta del almacén de datos utiliza un índice, una tabla que contiene los resultados de la consulta en el orden deseado. Una aplicación App Engine define sus índices en un archivo de configuración con el nombre index.yaml. El servidor web de desarrollo añade automáticamente sugerencias a este archivo a medida que encuentra consultas que no disponen aún de índices configurados. Para configurar manualmente los índices, edita el archivo antes de subir la aplicación.
El mecanismo de consultas basado en índices admite los tipos de consultas más habituales, pero no admite determinados tipos de consultas procedentes de otras tecnologías de bases de datos a los que es posible que estés acostumbrado. A continuación, se describen las restricciones que se aplican a las consultas y sus explicaciones.
Una consulta recupera entidades del almacén de datos que cumplen un conjunto de condiciones. La consulta especifica un tipo de entidad, cero o más condiciones basadas en valores de propiedad de la entidad (a veces llamados "filtros") y cero o más descripciones de criterios de ordenación. Al ejecutar una consulta, se extraen todas las entidades del tipo concreto que cumplen todas las condiciones especificadas, ordenadas de la forma descrita.
El API Python del almacén de datos proporciona dos interfaces que permiten preparar y ejecutar consultas: la interfaz Query, que utiliza métodos para preparar consultas, y la interfaz GqlQuery, que utiliza un lenguaje de consulta parecido a SQL (llamado GQL) para preparar la consulta a partir de una cadena de consulta. Estas interfaces se describen más detalladamente en Creación, obtención y eliminación de datos: obtención de entidades mediante una consulta y en las páginas de referencia correspondientes.
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
city = db.StringProperty()
birth_year = db.IntegerProperty()
height = db.IntegerProperty()
# The Query interface prepares a query using instance methods.
q = Person.all()
q.filter("last_name =", "Smith")
q.filter("height <", 72)
q.order("-height")
# The GqlQuery interface prepares a query using a GQL query string.
q = db.GqlQuery("SELECT * FROM Person " +
"WHERE last_name = :1 AND height < :2 " +
"ORDER BY height DESC",
"Smith", 72)
# The query is not executed until results are accessed.
results = q.fetch(5)
for p in results:
print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height)
Un filtro contiene un nombre de propiedad, un operador de comparación y un valor. Una entidad pasa el filtro si dispone de una propiedad para el nombre determinado y su valor es comparable con el del valor determinado como describe el operador. La entidad es el resultado de la consulta si esta pasa todos sus filtros.
El operador de filtro se puede utilizar para lo siguiente:
< menor que<= menor que o igual a= igual a> mayor que>= mayor que o igual a!= no igual aIN igual a cualquiera de los valores de la lista proporcionadaEn realidad, el operador != realiza dos consultas: una donde todos los demás filtros son el mismo y el filtro "no igual a" se sustituye por un filtro "menor que" y otra donde el filtro "no igual a" se sustituye por un filtro "mayor que". Los resultados se fusionan en orden. Como se describe a continuación en la sección sobre los filtros de desigualdad, una consulta sólo puede disponer de un filtro "no igual a" y no puede disponer de ningún otro filtro de desigualdad.
El operador IN también realiza múltiples consultas, una por cada elemento del valor de la lista proporcionada donde los demás filtros son el mismo y el filtro IN se sustituye por un filtro "no igual a". Los resultados se fusionan en el orden de los elementos de la lista. Si una consulta dispone de más de un filtro IN, esta se realiza como varias consultas, una por cada combinación de valores de los filtros IN.
Una consulta única que contenga los operadores != y IN tiene un límite de 30 subconsultas.
El almacén de datos de App Engine mantiene un índice para cada consulta que una aplicación pretende realizar. A medida que la aplicación realiza cambios en las entidades del almacén de datos, el almacén actualiza los índices con los resultados correctos. Cuando la aplicación ejecuta una consulta, el almacén de datos extrae los resultados directamente del índice correspondiente.
Una aplicación tiene un índice para cada combinación de tipo, propiedad de filtro y operador y, además, un criterio de ordenación utilizado en una consulta. Ten en cuenta la consulta del ejemplo, especificada en GQL:
SELECT * FROM Person WHERE last_name = "Smith"
AND height < 72
ORDER BY height DESC
El índice de esta consulta es una tabla de claves para entidades del tipo Person, con columnas para los valores de las propiedades height, last_name y . El índice se clasifica por height en orden descendente.
Dos consultas con el mismo formato pero con distintos valores de filtro utilizan el mismo índice. Por ejemplo, la siguiente consulta utiliza el mismo índice que la consulta anterior:
SELECT * FROM Person WHERE last_name = "Jones"
AND height < 63
ORDER BY height DESC
El almacén de datos ejecuta una consulta mediante los siguientes pasos:
Cada tabla de índice contiene columnas para cada una de las propiedades utilizadas en un filtro o criterio de ordenación. Las filas se ordenan según los siguientes aspectos, en orden:
Nota: en los índices, los filtros IN se gestionan como los filtros = y los filtros != se gestionan como otros filtros de desigualdad.
Esto coloca todos los resultados de cada posible consulta que utilice este índice en filas consecutivas de la tabla.
Sugerencia: los filtros de consulta no tienen una forma explícita de buscar correspondencias de sólo una parte de un valor de cadena, pero puedes falsear coincidencias con un prefijo utilizando filtros de desigualdad:
db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2", "abc", u"abc" + u"\ufffd")
Esto coincide con todas las entidades MyModel con una propiedad de cadena prop que comience por los caracteres abc. La cadena de Unicode u"\ufffd" representa el carácter Unicode más largo posible. Si los valores de propiedad se ordenan en un índice, los valores que se encuentran dentro de este intervalo son todos los valores que comienzan por el prefijo proporcionado.
Este mecanismo admite una amplia gama de consultas y resulta apropiado para la mayoría de las aplicaciones. No obstante, no admite algunos tipos de consultas procedentes de otras tecnologías de bases de datos a los que es posible que estés acostumbrado.
Un índice sólo contiene entidades cuyas propiedades aparecen en el índice. Si una propiedad de una entidad no aparece en el índice, dicha entidad no aparecerá en el índice y nunca será el resultado de la consulta que utilice el índice.
Ten en cuenta que el almacén de datos de App Engine distingue entre una entidad que no tiene una propiedad y una entidad que tiene una propiedad pero cuyo valor es nulo (None). Si deseas que todas las entidades de un tipo sean un posible resultado de una solicitud, puedes utilizar un modelo de datos que asigne un valor predeterminado (como None) a propiedades empleadas por filtros de consulta.
Las propiedades con valores del tipo de valor texto largo (Text) o del tipo de valor binario largo (Blob) no se incluyen en índices, por lo que las consultas no las encuentran.
Dado que estos valores de propiedad no se indexan, una consulta con un filtro o criterio de ordenación relacionado con una propiedad nunca coincidirá con una entidad cuyo valor de propiedad sea Text o Blob. Las propiedades con estos valores se comportan como si la propiedad no estuviera establecida en relación con los criterios de ordenación y filtros de la consulta.
Cuando dos entidades tienen propiedades con el mismo nombre pero con diferente tipo de valor, el índice de propiedad ordena las entidades primero según el tipo de valor y, a continuación, según un orden adecuado al tipo. Por ejemplo, si dos entidades tienen una propiedad denominada "age", una con un valor entero y otra con un valor de cadena, la entidad con el valor entero aparecerá siempre antes que la entidad con el valor de cadena, cuando se hayan ordenado según la propiedad "Age", independientemente de los valores en sí.
Cabe destacar esto en el caso de los números enteros y de punto flotante, a los que el almacén de datos trata como tipos independientes. Una propiedad con valor entero 38 se ordena antes que una propiedad con valor de punto flotante 37.5, ya que todos los enteros se ordenan con anterioridad a los flotantes.
App Engine genera índices para diversas consultas sencillas de forma predeterminada. Para otras consultas, la aplicación debe especificar los índices que necesita en un archivo de configuración con el nombre index.yaml. Si la aplicación que se está ejecutando sobre App Engine intenta realizar una consulta para la que no existe un índice correspondiente (proporcionado de forma predeterminada o descrito en index.yaml), la consulta fallará.
App Engine proporciona índices automáticos para los siguientes formatos de consultas:
Para el resto de formatos de consultas es necesario especificar sus índices en index.yaml, incluidas:
El servidor web de desarrollo hace que la gestión de la configuración del índice sea más fácil. En lugar de fallar en la ejecución de una consulta que no dispone de índice y que lo necesita, el servidor web de desarrollo puede generar configuración para un índice que permitiría que la solicitud se realice con éxito. Si la prueba local de tu aplicación ejecuta cada consulta posible que vaya a realizar la aplicación (cada combinación de tipo, ancestros, filtro y criterio de ordenación), las entradas generadas representarán un conjunto completo de índices. Si tu prueba no ejecuta cada posible formato de consulta, puedes consultar y ajustar la configuración de índice antes de subir la aplicación.
App Engine genera índices para diversas consultas sencillas de forma predeterminada. Para otras consultas, la aplicación debe especificar los índices que necesita en un archivo de configuración con el nombre index.yaml. Si la aplicación que se está ejecutando sobre App Engine intenta realizar una consulta para la que no existe un índice correspondiente (proporcionado de forma predeterminada o descrito en index.yaml), la consulta fallará.
index.yaml describe cada tabla de índice, incluidos el tipo, las propiedades necesarias para los filtros de consulta y los criterios de ordenación y si la consulta utiliza o no una cláusula ancestor (Query.ancestor() o una cláusula GQL ANCESTOR IS). Las propiedades aparecen en el orden especificado por los criterios de ordenación: primero las propiedades utilizadas en filtros de igualdad o IN, seguidas de las propiedades utilizadas en filtros de desigualdad y, a continuación, los criterios de ordenación de los resultados de la consulta y sus direcciones.
Tomemos como ejemplo una vez más la siguiente consulta de muestra:
SELECT * FROM Person WHERE last_name = "Smith"
AND height < 72
ORDER BY height DESC
Si la aplicación ejecutó sólo esta consulta (y posiblemente otras consultas parecidas, pero con diferentes valores para "Smith" y 72), el archivo index.yaml podría ser así:
indexes:
- kind: Person
properties:
- name: last_name
- name: height
direction: desc
Al crear o actualizar una entidad, también se actualizan todos los índices correspondientes. El número de índices que se aplican a una entidad afecta al tiempo que se tarda en crear o actualizar la entidad.
Para obtener más información sobre la sintaxis de index.yaml, consulta Configuración de índices.
Mediante el uso del nombre especial __key__ en lugar del nombre de la propiedad, las claves de entidades pueden ser el asunto de un filtro de consultas o de la ordenación. El almacén de datos considera el valor de clave completo para esas consultas, incluida la ruta de la entidad principal de la entidad, el tipo y la cadena de nombre de clave asignada por la aplicación o la ID numérica asignada por el sistema.
Puesto que una clave de entidad es única para todas las entidades del sistema, las consultas de clave facilitan la recuperación de un determinado tipo de entidades en lotes como, por ejemplo, un volcado de lotes del contenido del almacén de datos __key__. A diferencia de la desviación, esto funciona de forma eficaz para cualquier número de entidades. Por ejemplo:
class MainHandler(webapp.RequestHandler):
def get(self):
query = Entity.gql('ORDER BY __key__')
# Use a query parameter to keep track of the last key of the last
# batch, to know where to start the next batch.
last_key_str = self.request.get('last')
if last_key_str:
last_key = db.Key(last_key_str)
query = Entity.gql('WHERE __key__ > :1 ORDER BY __key__', last_key)
# For batches of 20, fetch 21, then use result #20 as the "last"
# if there is a 21st.
entities = query.fetch(21)
new_last_key_str = None
if len(entities) == 21:
new_last_key_str = str(entities[19].key())
# Return the data and new_last_key_str. Client would use
# http://...?last=new_last_key_str to fetch the next batch.
# ...
Las claves se ordenan primero por ruta principal y, a continuación, por tipo y por nombre de clave o ID. Los nombres de clave y de tipos son cadenas y se ordenan por valor de byte. Las ID son enteras y se ordenan de forma numérica. Si las entidades con el mismo tipo y principal utilizan una mezcla de cadenas de nombre de clave e ID numéricas, las entidades con ID numéricas se consideran que tienen que ser inferiores a las cadenas de nombre de clave. La comparación de los elementos de la ruta principal se realiza de forma similar: por tipo (cadena), por nombre de clave (cadena) o ID (número).
Las consultas que implican claves utilizan índices del mismo modo que las consultas que implican propiedades, pero con una diferencia: a diferencia de una consulta con una propiedad, una consulta con un filtro de igualdad en la clave que también tenga filtros adicionales debe emplear un índice personalizado definido en el archivo de configuración del índice de la aplicación. Como con todas las consultas, el servidor web de desarrollo crea entradas de configuración adecuadas en este archivo cuando se prueba una consulta que requiere un índice personalizado.
La naturaleza del mecanismo de consultas basado en índices impone unas cuantas restricciones con respecto a lo que se puede hacer.
Una condición de filtro de consulta o un criterio de ordenación de una propiedad también implica la condición de que la entidad tenga un valor para la propiedad.
No es necesario que una entidad de almacén de datos tenga el mismo valor para una propiedad que otras entidades del mismo tipo. Un filtro sobre una propiedad sólo puede coincidir con una entidad con un valor para la propiedad. Las entidades sin un valor para una propiedad que se utilicen en un filtro o criterio de ordenación se omitirán del índice generado para la consulta.
No es posible realizar una consulta que solicite entidades que no tengan una propiedad determinada. Una alternativa es crear una propiedad fija (modelada) con un valor predeterminado de None y, a continuación, crear un filtro para las entidades con None como valor de propiedad.
Una consulta sólo puede utilizar filtros de desigualdad (<, <=, >=, >, !=) en una única propiedad en todos sus filtros.
Por ejemplo, esta consulta está permitida:
SELECT * FROM Person WHERE birth_year >= :min
AND birth_year <= :max
No obstante, esta consulta no está permitida porque utiliza filtros de desigualdad en dos propiedades distintas de la misma consulta:
SELECT * FROM Person WHERE birth_year >= :min_year
AND height >= :min_height # ERROR
Los filtros pueden combinar comparaciones de igualdad (=) para distintas propiedades de la misma consulta, incluidas consultas con una o más condiciones de desigualdad en una propiedad. Lo siguiente está permitido:
SELECT * FROM Person WHERE last_name = :last_name
AND city = :city
AND birth_year >= :min_year
El mecanismo de consulta se basa en que todos los resultados para una consulta serán adyacentes entre sí en la tabla de índice para evitar tener que examinar la tabla entera buscando los resultados. Una sola tabla de índice no puede representar varios filtros de desigualdad en múltiples propiedades manteniendo a la vez todos los resultados consecutivos en la tabla.
Si una consulta tiene un filtro con una comparación de desigualdad y uno o varios criterios de ordenación, la consulta deberá incluir un criterio de ordenación para la desigualdad, que deberá aparecer antes que los criterios de ordenación aplicados a otras propiedades.
Esta consulta no es válida porque utiliza un filtro de desigualdad y no ordena por la propiedad filtrada:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY last_name # ERROR
Igualmente, esta consulta no es válida porque no ordena por la propiedad filtrada antes de ordenar por otras propiedades:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY last_name, birth_year # ERROR
Esta consulta es válida:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY birth_year, last_name
Para obtener todos los resultados que coinciden con un filtro de desigualdad, una consulta busca en la tabla de índice la primera fila coincidente y, a continuación, devuelve todos los resultados consecutivos hasta que encuentra una fila que no coincide. Para que las filas consecutivas representen el conjunto de resultados completo, las filas se deben ordenar por filtro de desigualdad antes que por cualquier otro criterio de ordenación.
Debido a la forma en que se indexan las propiedades con varios valores, el criterio de ordenación de estas propiedades es inusual:
Este criterio de ordenación tiene la consecuencia inusual de que [1, 9] aparece antes de [4, 5, 6, 7], tanto en orden ascendente como en orden descendente.
Una advertencia importante es la relacionada con aquellas consultas con un filtro de igualdad y un criterio de ordenación en una propiedad con múltiples valores. En estas consultas, se hace caso omiso del criterio de ordenación. En el caso de las propiedades con un único valor, se trata de una optimización sencilla. Cada resultado tendrá el mismo valor para la propiedad, por lo que no será necesario ordenar más los resultados.
No obstante, las propiedades con varios valores pueden tener valores adicionales. Dado que se ha hecho caso omiso del criterio de ordenación, es posible que los resultados de la consulta se devuelvan en un orden distinto al que se habría obtenido de haberse aplicado el criterio de ordenación. (La restauración del criterio de ordenación desechado resulta costosa y requiere índices adicionales; además, este uso es poco habitual, por lo que el diseñador de consultas lo excluye).
Como se ha descrito anteriormente, todas las propiedades (que no tienen un valor Text o Blob) de todas las entidades se añaden al menos a una tabla de índice, incluido un índice sencillo que se proporciona de forma predeterminada y los índices descritos en el archivo index.yaml de la aplicación que hace referencia a la propiedad. En el caso de una entidad que tenga un valor para cada propiedad, App Engine almacena un valor de propiedad en su índice sencillo y una vez por cada ocasión en que se haga referencia a la propiedad en un índice personalizado. Todas las entradas de índice se deben actualizar cada vez que el valor de la propiedad cambie. Por tanto, cuantos más índices hagan referencia a la propiedad, más tiempo tardará en actualizarla.
Para evitar que la actualización de una propiedad tarde demasiado tiempo, el almacén de datos limita el número de entradas de índice que puede tener una única entidad. El límite es grande y la mayoría de las aplicaciones no lo perciben. No obstante, existen determinadas circunstancias en las que es posible encontrarse con el límite. Por ejemplo, una entidad con muchas propiedades de valor único puede exceder el límite de entradas de índice.
Las propiedades con varios valores almacenan cada valor en un índice como entradas independientes. Una entidad con una única propiedad que tenga muchos valores puede exceder el límite de entradas del índice.
Los índices personalizados que hacen referencia a varias propiedades con varios valores pueden aumentar mucho su tamaño con unos cuantos valores. Para registrar completamente dichas propiedades, la tabla de índice debe incluir una fila para cada permutación de los valores de cada propiedad del índice.
Por ejemplo, el siguiente índice (descrito en la sintaxis de index.yaml) incluye las propiedades x y y de las entidades del tipo MyModel:
indexes: - kind: MyModel properties: - name: x - name: y
El siguiente código crea una entidad con dos valores para la propiedad x y dos valores para la propiedad y:
class MyModel(db.Expando): pass e2 = MyModel() e2.x = ['red', 'blue'] e2.y = [1, 2] e2.put()
Para representar con exactitud estos valores, el índice debe almacenar doce valores de propiedad: dos para los índices integrados en x y y y dos para cada una de las cuatro permutaciones de x y y en el índice personalizado. Con varios valores de propiedades con varios valores, esto puede significar que un índice debe almacenar varias entradas de índice para una única entidad. Puedes ejecutar un índice que haga referencia a varias propiedades con varios valores, un "índice de ampliación", porque puede aumentar de tamaño con tan sólo unos valores.
Si put() da lugar a un número de entradas de índice que excede el límite, la llamada generará una excepción. Si creas un índice nuevo que pueda contener un número de entradas de índice que exceda el límite para cualquier entidad durante su creación, las consultas relacionadas con el índice generarán un error y el índice aparecerá con el estado "Error" en la consola de administración.
Para gestionar índices con estado "Error", en primer lugar elimínalos de tu archivo index.yaml y ejecuta appcfg.py vacuum_indexes. A continuación, reformula la definición del índice y las consultas correspondientes, o elimina las entidades que hagan que el índice se "amplíe". Por último, vuelve a añadir el índice a index.yaml y ejecuta appcfg.py update_indexes.
Para evitar los índices de ampliación, evita aquellas consultas que necesiten un índice personalizado con una propiedad de lista. Como se ha descrito anteriormente, esto incluye consultas con varios criterios de ordenación, una mezcla de filtros de igualdad y desigualdad y filtros de ancestros.