claim search uses different tag filtering approaches depeding on query type

This commit is contained in:
Lex Berezhny 2019-07-08 15:49:32 -04:00
parent c1c7e30ec9
commit 8c878f8e25
2 changed files with 49 additions and 19 deletions

View file

@ -35,7 +35,7 @@ STREAM_TYPES = {
} }
def _apply_constraints_for_array_attributes(constraints, attr, cleaner): def _apply_constraints_for_array_attributes(constraints, attr, cleaner, for_count=False):
any_items = cleaner(constraints.pop(f'any_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH] any_items = cleaner(constraints.pop(f'any_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH]
if any_items: if any_items:
constraints.update({ constraints.update({
@ -44,9 +44,18 @@ def _apply_constraints_for_array_attributes(constraints, attr, cleaner):
values = ', '.join( values = ', '.join(
f':$any_{attr}{i}' for i in range(len(any_items)) f':$any_{attr}{i}' for i in range(len(any_items))
) )
constraints[f'claim.claim_hash__in#_any_{attr}'] = f""" if for_count:
SELECT DISTINCT claim_hash FROM {attr} WHERE {attr} IN ({values}) constraints[f'claim.claim_hash__in#_any_{attr}'] = f"""
""" SELECT claim_hash FROM {attr} WHERE {attr} IN ({values})
"""
else:
constraints[f'#_any_{attr}'] = f"""
EXISTS(
SELECT 1 FROM {attr} WHERE
claim.claim_hash={attr}.claim_hash
AND {attr} IN ({values})
)
"""
all_items = cleaner(constraints.pop(f'all_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH] all_items = cleaner(constraints.pop(f'all_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH]
if all_items: if all_items:
@ -57,10 +66,19 @@ def _apply_constraints_for_array_attributes(constraints, attr, cleaner):
values = ', '.join( values = ', '.join(
f':$all_{attr}{i}' for i in range(len(all_items)) f':$all_{attr}{i}' for i in range(len(all_items))
) )
constraints[f'claim.claim_hash__in#_all_{attr}'] = f""" if for_count:
SELECT claim_hash FROM {attr} WHERE {attr} IN ({values}) constraints[f'claim.claim_hash__in#_all_{attr}'] = f"""
GROUP BY claim_hash HAVING COUNT({attr}) = :$all_{attr}_count SELECT claim_hash FROM {attr} WHERE {attr} IN ({values})
""" GROUP BY claim_hash HAVING COUNT({attr}) = :$all_{attr}_count
"""
else:
constraints[f'#_all_{attr}'] = f"""
{len(all_items)}=(
SELECT count(*) FROM {attr} WHERE
claim.claim_hash={attr}.claim_hash
AND {attr} IN ({values})
)
"""
not_items = cleaner(constraints.pop(f'not_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH] not_items = cleaner(constraints.pop(f'not_{attr}s', []))[:ATTRIBUTE_ARRAY_MAX_LENGTH]
if not_items: if not_items:
@ -70,9 +88,18 @@ def _apply_constraints_for_array_attributes(constraints, attr, cleaner):
values = ', '.join( values = ', '.join(
f':$not_{attr}{i}' for i in range(len(not_items)) f':$not_{attr}{i}' for i in range(len(not_items))
) )
constraints[f'claim.claim_hash__not_in#_not_{attr}'] = f""" if for_count:
SELECT DISTINCT claim_hash FROM {attr} WHERE {attr} IN ({values}) constraints[f'claim.claim_hash__not_in#_not_{attr}'] = f"""
""" SELECT claim_hash FROM {attr} WHERE {attr} IN ({values})
"""
else:
constraints[f'#_not_{attr}'] = f"""
NOT EXISTS(
SELECT 1 FROM {attr} WHERE
claim.claim_hash={attr}.claim_hash
AND {attr} IN ({values})
)
"""
class SQLDB: class SQLDB:
@ -745,7 +772,7 @@ class SQLDB:
r(self.update_claimtrie, height, recalculate_claim_hashes, deleted_claim_names, forward_timer=True) r(self.update_claimtrie, height, recalculate_claim_hashes, deleted_claim_names, forward_timer=True)
r(calculate_trending, self.db, height, self.main.first_sync, daemon_height) r(calculate_trending, self.db, height, self.main.first_sync, daemon_height)
def get_claims(self, cols, join=True, **constraints): def get_claims(self, cols, for_count=False, **constraints):
if 'order_by' in constraints: if 'order_by' in constraints:
sql_order_by = [] sql_order_by = []
for order_by in constraints['order_by']: for order_by in constraints['order_by']:
@ -776,7 +803,7 @@ class SQLDB:
if constraints.pop('is_controlling', False): if constraints.pop('is_controlling', False):
if {'sequence', 'amount_order'}.isdisjoint(constraints): if {'sequence', 'amount_order'}.isdisjoint(constraints):
join = True for_count = False
constraints['claimtrie.claim_hash__is_not_null'] = '' constraints['claimtrie.claim_hash__is_not_null'] = ''
if 'sequence' in constraints: if 'sequence' in constraints:
constraints['order_by'] = 'claim.activation_height ASC' constraints['order_by'] = 'claim.activation_height ASC'
@ -864,14 +891,14 @@ class SQLDB:
if 'fee_currency' in constraints: if 'fee_currency' in constraints:
constraints['claim.fee_currency'] = constraints.pop('fee_currency').lower() constraints['claim.fee_currency'] = constraints.pop('fee_currency').lower()
_apply_constraints_for_array_attributes(constraints, 'tag', clean_tags) _apply_constraints_for_array_attributes(constraints, 'tag', clean_tags, for_count)
_apply_constraints_for_array_attributes(constraints, 'language', lambda _: _) _apply_constraints_for_array_attributes(constraints, 'language', lambda _: _, for_count)
_apply_constraints_for_array_attributes(constraints, 'location', lambda _: _) _apply_constraints_for_array_attributes(constraints, 'location', lambda _: _, for_count)
select = f"SELECT {cols} FROM claim" select = f"SELECT {cols} FROM claim"
sql, values = query( sql, values = query(
select if not join else select+""" select if for_count else select+"""
LEFT JOIN claimtrie USING (claim_hash) LEFT JOIN claimtrie USING (claim_hash)
LEFT JOIN claim as channel ON (claim.channel_hash=channel.claim_hash) LEFT JOIN claim as channel ON (claim.channel_hash=channel.claim_hash)
""", **constraints """, **constraints
@ -886,7 +913,7 @@ class SQLDB:
constraints.pop('offset', None) constraints.pop('offset', None)
constraints.pop('limit', None) constraints.pop('limit', None)
constraints.pop('order_by', None) constraints.pop('order_by', None)
count = self.get_claims('count(*)', join=False, **constraints) count = self.get_claims('count(*)', for_count=True, **constraints)
return count[0][0] return count[0][0]
def _search(self, **constraints): def _search(self, **constraints):

View file

@ -93,7 +93,10 @@ def constraints_to_sql(constraints, joiner=' AND ', prepend_key=''):
if '#' in key: if '#' in key:
key, tag = key[:key.index('#')], key[key.index('#')+1:] key, tag = key[:key.index('#')], key[key.index('#')+1:]
col, op, key = key, '=', key.replace('.', '_') col, op, key = key, '=', key.replace('.', '_')
if key.startswith('$'): if not key:
sql.append(constraint)
continue
elif key.startswith('$'):
values[key] = constraint values[key] = constraint
continue continue
elif key.endswith('__not'): elif key.endswith('__not'):