in src/google/appengine/datastore/datastore_index.py [0:0]
def MinimalCompositeIndexForQuery(query, index_defs):
"""Computes the minimal composite index for this query.
Unlike `datastore_index.CompositeIndexForQuery`, this function takes into
account indexes that already exist in the system.
Args:
query: The `datastore_pb.Query` to compute suggestions for.
index_defs: A list of `datastore_index.Index` objects that already exist.
Returns:
`None` if no index is needed, otherwise the minimal index in the form
`(is_most_efficient, kind, ancestor, properties)`. Where `is_most_efficient`
is a boolean denoting if the suggested index is the most efficient (i.e.,
the one returned by `datastore_index.CompositeIndexForQuery`). kind and
ancestor are the same variables returned by
`datastore_index.CompositeIndexForQuery`. properties is a tuple consisting
of the prefix and postfix properties returend by
`datastore_index.CompositeIndexForQuery`.
"""
required, kind, ancestor, (prefix, postfix) = CompositeIndexForQuery(query)
if not required:
return None
remaining_dict = {}
for definition in index_defs:
if (kind != definition.kind or
(not ancestor and definition.ancestor)):
continue
_, _, index_props = IndexToKey(definition)
index_prefix = _MatchPostfix(postfix, index_props)
if index_prefix is None:
continue
remaining_index_props = set([prop.name for prop in index_prefix])
if remaining_index_props - prefix:
continue
index_postfix = tuple(index_props[len(index_prefix):])
remaining = remaining_dict.get(index_postfix)
if remaining is None:
remaining = prefix.copy(), ancestor
props_remaining, ancestor_remaining = remaining
props_remaining -= remaining_index_props
if definition.ancestor:
ancestor_remaining = False
if not (props_remaining or ancestor_remaining):
return None
if (props_remaining, ancestor_remaining) == remaining:
continue
remaining_dict[index_postfix] = (props_remaining, ancestor_remaining)
if not remaining_dict:
return (True, kind, ancestor, (prefix, postfix))
def calc_cost(minimal_props, minimal_ancestor):
result = len(minimal_props)
if minimal_ancestor:
result += 2
return result
minimal_postfix, remaining = remaining_dict.popitem()
minimal_props, minimal_ancestor = remaining
minimal_cost = calc_cost(minimal_props, minimal_ancestor)
for index_postfix, (props_remaining,
ancestor_remaining) in (list(remaining_dict.items())):
cost = calc_cost(props_remaining, ancestor_remaining)
if cost < minimal_cost:
minimal_cost = cost
minimal_postfix = index_postfix
minimal_props = props_remaining
minimal_ancestor = ancestor_remaining
props = frozenset(minimal_props), (minimal_postfix, frozenset(), frozenset())
return False, kind, minimal_ancestor, props