Exemple #1
0
def create_response(mimetypes: List[str], bindings: List[Dict[str, str]], next_page: Optional[str], stats: dict, skol_url: str) -> Response:
    """Create an HTTP response for the results of SPARQL query execution.

    Args:
      * mimetypes: mimetypes from the input HTTP request.
      * bindings: list of query results.
      * next_link: Link to a SaGe saved plan. Use `None` if there is no one, i.e., the query execution has completed during the quantum.
      * stats: Statistics about query execution.
      * skol_url: URL used for the skolemization of blank nodes.

    Returns:
      An HTTP response built from the input mimetypes and the SPARQL query results.
    """
    if "application/json" in mimetypes:
        iterator = responses.raw_json_streaming(bindings, next_page, stats, skol_url)
        return StreamingResponse(iterator, media_type="application/json")
    elif "application/sparql-results+json" in mimetypes:
        iterator = responses.w3c_json_streaming(bindings, next_page, stats, skol_url)
        return StreamingResponse(iterator, media_type="application/json")
    elif "application/xml" in mimetypes or "application/sparql-results+xml" in mimetypes:
        iterator = responses.w3c_xml(bindings, next_page, stats)
        return Response(iterator, media_type="application/xml")
    return JSONResponse({
        "bindings": bindings,
        "next": next_page,
        "stats": stats
    })
def execute_query(query, default_graph_uri, next_link, dataset, mimetype, url):
    """
        Execute a query using the SageEngine and returns the appropriate HTTP response.
        Any failure will results in a rollback/abort on the current query execution.
    """
    graph = None
    try:
        graph_name = format_graph_uri(default_graph_uri, url)
        if not dataset.has_graph(graph_name):
            logging.error("No RDF graph matching the default URI provided was found.")
            return sage_http_error("No RDF graph matching the default URI provided was found.")
        graph = dataset.get_graph(graph_name)
        # decode next_link or build query execution plan
        cardinalities = dict()
        start = time()

        if next_link is not None:
            plan = load(decode_saved_plan(next_link), dataset)
        else:
            plan, cardinalities = parse_query(query, dataset, graph_name, url)
        loading_time = (time() - start) * 1000
        # execute query
        engine = SageEngine()
        quota = graph.quota / 1000
        max_results = graph.max_results
        bindings, saved_plan, is_done = engine.execute(plan, quota, max_results)

        # commit (if necessary)
        graph.commit()

        # compute controls for the next page
        start = time()
        next_page = None
        if not is_done:
            next_page = encode_saved_plan(saved_plan)
        exportTime = (time() - start) * 1000
        stats = {"cardinalities": cardinalities, "import": loading_time, "export": exportTime}

        # send response
        if mimetype == "application/sparql-results+json":
            return Response(responses.w3c_json_streaming(bindings, next_page, stats, url),
                            content_type='application/json')
        if mimetype == "application/xml" or mimetype == "application/sparql-results+xml":
            return Response(responses.w3c_xml(bindings, next_page, stats), content_type="application/xml")
        if mimetype == "application/json":
            return Response(responses.raw_json_streaming(bindings, next_page, stats, url),
                            content_type='application/json')
        # otherwise, return the HTML version
        return render_template("sage_page.html", query=query, default_graph_uri=default_graph_uri, bindings=bindings,
                               next_page=next_page, stats=stats)
    except Exception as err:
        # abort all ongoing transactions (if required)
        # then forward the exception to the main loop
        logging.error(f"sage execute_query error: {err}")
        if graph is not None:
            graph.abort()
        raise err
    def sparql_query(graph_name):
        """WARNING: old API, deprecated"""
        print("WARNING: old API, deprecated on /sparql/{}".format(graph_name))
        graph = dataset.get_graph(graph_name)
        if graph is None:
            abort(404)

        logger.debug('[/sparql/] Corresponding dataset found')
        mimetype = request.accept_mimetypes.best_match([
            "application/json", "application/xml",
            "application/sparql-results+json", "application/sparql-results+xml"
        ])
        url = secure_url(request.url)
        try:
            # A GET request always returns the homepage of the dataset
            if request.method == "GET" or (not request.is_json):
                dinfo = graph.describe(url)
                to_publish = dumps(dinfo) if graph.config()['publish'] else None
                dinfo['@id'] = url
                void_desc = {
                    "nt": VoidDescriptor(url, graph).describe("ntriples"),
                    "ttl": VoidDescriptor(url, graph).describe("turtle"),
                    "xml": VoidDescriptor(url, graph).describe("xml")
                }
                queries = [q for q in graph.example_queries if q["publish"]]
                return render_template("website/sage_dataset.html", dataset_info=dinfo, void_desc=void_desc,
                                       to_publish=to_publish, queries=queries)

            engine = SageEngine()
            post_query, err = QueryRequest().load(request.get_json())
            if err is not None and len(err) > 0:
                return Response(format_marshmallow_errors(err), status=400)
            quota = graph.quota / 1000
            max_results = graph.max_results

            # Load next link
            next_link = None
            if 'next' in post_query:
                next_link = decode_saved_plan(post_query["next"])

            # build physical query plan, then execute it with the given quota
            start = time()
            plan, cardinalities = build_query_plan(post_query["query"], dataset, graph_name, next_link)
            loading_time = (time() - start) * 1000  # convert in milliseconds
            bindings, saved_plan, is_done = engine.execute(plan, quota, max_results)

            # commit (if necessary)
            graph.commit()

            # compute controls for the next page
            start = time()
            next_page = None
            if not is_done:
                next_page = encode_saved_plan(saved_plan)
            exportTime = (time() - start) * 1000  # convert in milliseconds
            stats = {"cardinalities": cardinalities, "import": loading_time, "export": exportTime}

            if mimetype == "application/sparql-results+json":
                res = Response(responses.w3c_json_streaming(bindings, next_page, stats, url),
                               content_type='application/json')
            if mimetype == "application/xml" or mimetype == "application/sparql-results+xml":
                res = Response(responses.w3c_xml(bindings, next_page, stats), content_type="application/xml")
            else:
                res = Response(responses.raw_json_streaming(bindings, next_page, stats, url),
                               content_type='application/json')
            # set deprecation warning in headers
            res.headers.add("Warning",
                            "199 SaGe/2.0 \"You are using a deprecated API. Consider uppgrading to the SaGe SPARQL query API. See http://sage.univ-nantes.fr/documentation fore more details.\"")
            return res
        except Exception as e:
            logger.error(e)
            abort(500)