query.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import logging
  2. from io import BytesIO
  3. from rdflib import URIRef
  4. from lakesuperior import env
  5. from lakesuperior.dictionaries.namespaces import ns_collection as nsc
  6. from lakesuperior.dictionaries.namespaces import ns_mgr as nsm
  7. logger = logging.getLogger(__name__)
  8. rdfly = env.app_globals.rdfly
  9. rdf_store = env.app_globals.rdf_store
  10. operands = ('_id', '=', '!=', '<', '>', '<=', '>=')
  11. """
  12. Available term comparators for term query.
  13. The ``_uri`` term is used to match URIRef terms, all other comparators are
  14. used against literals.
  15. """
  16. def triple_match(s=None, p=None, o=None, return_full=False):
  17. """
  18. Query store by matching triple patterns.
  19. Any of the ``s``, ``p`` or ``o`` terms can be None to represent a wildcard.
  20. This method is for triple matching only; it does not allow to query, nor
  21. exposes to the caller, any context.
  22. :param rdflib.term.Identifier s: Subject term.
  23. :param rdflib.term.Identifier p: Predicate term.
  24. :param rdflib.term.Identifier o: Object term.
  25. :param bool return_full: if ``False`` (the default), the returned values
  26. in the set are the URIs of the resources found. If True, the full set
  27. of matching triples is returned.
  28. :rtype: set(tuple(rdflib.term.Identifier){3}) or set(rdflib.URIRef)
  29. :return: Matching resource URIs if ``return_full`` is false, or
  30. matching triples otherwise.
  31. """
  32. with rdf_store.txn_ctx():
  33. matches = rdf_store.triples((s, p, o), None)
  34. # Strip contexts and de-duplicate.
  35. qres = (
  36. {match[0] for match in matches} if return_full
  37. else {match[0][0] for match in matches})
  38. return qres
  39. def term_query(terms, or_logic=False):
  40. """
  41. Query resources by predicates, comparators and values.
  42. Comparators can be against literal or URIRef objects. For a list of
  43. comparators and their meanings, see the documentation and source for
  44. :py:data:`~lakesuperior.api.query.operands`.
  45. :param list(tuple{3}) terms: List of 3-tuples containing:
  46. - Predicate URI (rdflib.URIRef)
  47. - Comparator value (str)
  48. - Value to compare to (rdflib.URIRef or rdflib.Literal or str)
  49. :param bool or_logic: Whether to concatenate multiple query terms with OR
  50. logic (uses SPARQL ``UNION`` statements). The default is False (i.e.
  51. terms are concatenated as standard SPARQL statements).
  52. """
  53. qry_term_ls = []
  54. for i, term in enumerate(terms):
  55. if term['op'] not in operands:
  56. raise ValueError('Not a valid operand: {}'.format(term['op']))
  57. if term['op'] == '_id':
  58. qry_term = '?s {} {} .'.format(term['pred'], term['val'])
  59. else:
  60. oname = '?o_{}'.format(i)
  61. qry_term = '?s {0} {1}\nFILTER (str({1}) {2} "{3}") .'.format(
  62. term['pred'], oname, term['op'], term['val'])
  63. qry_term_ls.append(qry_term)
  64. if or_logic:
  65. qry_terms = '{\n' + '\n} UNION {\n'.join(qry_term_ls) + '\n}'
  66. else:
  67. qry_terms = '\n'.join(qry_term_ls)
  68. qry_str = '''
  69. SELECT ?s WHERE {{
  70. {}
  71. }}
  72. '''.format(qry_terms)
  73. logger.debug('Query: {}'.format(qry_str))
  74. with rdf_store.txn_ctx():
  75. qres = rdfly.raw_query(qry_str)
  76. return {row[0] for row in qres}
  77. def fulltext_lookup(pattern):
  78. """
  79. Look up one term by partial match.
  80. *TODO: reserved for future use. A `Whoosh
  81. <https://whoosh.readthedocs.io/>`__ or similar full-text index is
  82. necessary for this.*
  83. """
  84. pass
  85. def sparql_query(qry_str, fmt):
  86. """
  87. Send a SPARQL query to the triplestore.
  88. :param str qry_str: SPARQL query string. SPARQL 1.1 Query Language
  89. (https://www.w3.org/TR/sparql11-query/) is supported.
  90. :param str fmt: Serialization format. This varies depending on the
  91. query type (SELECT, ASK, CONSTRUCT, etc.). [TODO Add reference to
  92. RDFLib serialization formats]
  93. :rtype: BytesIO
  94. :return: Serialized SPARQL results.
  95. """
  96. with rdf_store.txn_ctx():
  97. qres = rdfly.raw_query(qry_str)
  98. out_stream = BytesIO(qres.serialize(format=fmt))
  99. return out_stream