Übung: Abfragen mit dem Java SDK in Azure Cosmos DB

Abgeschlossen

Sie haben nun Dokumente in Ihrer Anwendung erstellt und können diese aus Ihrer Anwendung abrufen. Das Azure Cosmos DB Java SDK verwendet SQL-Abfragen. Das .NET SDK bietet zusätzliche Unterstützung für LINQ-Abfragen, aber das Java SDK verfügt über keine analogen Möglichkeiten. Diese Lerneinheit konzentriert sich nicht auf die Ausführung von Abfragen im Portal, sondern auf die Ausführung von SQL-Abfragen in Ihrer Anwendung.

Hierbei werden die für Ihre Anwendung für Onlinehändler erstellten Benutzerdokumente verwendet, um diese Abfragen zu testen.

Ausführen von SQL-Abfragen

  1. Im folgenden Beispiel wird gezeigt, wie eine Abfrage über Ihren Java-Code in SQL ausgeführt werden kann. Kopieren Sie den Code, und fügen Sie ihn am Ende der Datei CosmosApp.java ein.

    /**
     * Execute a custom query on the Azure Cosmos DB container.
     * @param query Query String.
     */
    private static void executeSimpleQuery(final String query) {
    
        final int preferredPageSize = 10;
        CosmosQueryRequestOptions queryOptions = new CosmosQueryRequestOptions();
    
        CosmosPagedFlux<User> pagedFluxResponse = container.queryItems(
                query, queryOptions, User.class);
    
        logger.info("Running SQL query...");
    
        pagedFluxResponse.byPage(preferredPageSize).flatMap(fluxResponse -> {
            logger.info("Got a page of query result with " + fluxResponse.getResults().size()
                    + " items(s) and request charge of " + fluxResponse.getRequestCharge());
    
            logger.info("Item Ids " + fluxResponse
                    .getResults()
                    .stream()
                    .map(User::getId)
                    .collect(Collectors.toList()));
    
            return Flux.empty();
        }).blockLast();
    }
    

    Beachten Sie in diesem Code, dass wir das deklarative Datenfluss-Programmiermodell von Project Reactor erneut verwenden. Dieses Mal verwenden wir es, um Abfrageantwortseiten asynchron zu verarbeiten. Wir zeigen einen asynchronen Ansatz, da es in realen Anwendungsfällen Hunderte oder Tausende von Antworten auf eine Abfrage geben kann. Das Aggregieren von Abfrageantworten kann ein CPU-intensiver Task sein, der von der verbesserten Threadeffizienz der asynchronen Programmierung profitiert.

    Kurz gesagt: Hier ist ein hoher Durchsatz für das Verarbeiten von Abfrageantworten erforderlich bzw. ein hoher Seiten/Sekunde-Wert pro Thread. queryitems gibt die CosmosPagedFlux-Instanz pagedFluxResponse zurück, und pagedFluxResponse.byPage(preferredPageSize) erstellt eine Flux-Instanz. Diese ist die Quelle asynchroner Seitenereignisse. Die Vorgangspipeline innerhalb von .flatMap( ... ).blockLast();, die jeweils den von der Flux-Instanz ausgegebenen Ereignissen zugeordnet ist, wird auf der Abfrageantwortseite asynchron und pseudoparallel ausgeführt.

  2. Kopieren Sie den folgenden Code, und fügen Sie ihn vor dem Code zur Löschung des Dokuments in Ihrer basicOperations-Methode ein.

    executeSimpleQuery("SELECT * FROM User WHERE User.lastName = 'Pindakova'");
    
  3. Erstellen Sie CosmosApp.java in der IDE, und führen Sie das Programm aus, oder führen Sie das Programm im Terminal wie folgt aus:

    mvn clean package
    mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
    

    Die Ausgabe im Terminal sollte ungefähr wie folgt aussehen:

    INFO: Database and container validation complete
    INFO: User 1 already exists in the database
    INFO: User 2 already exists in the database
    INFO: Read User 1
    INFO: Replaced last name for Suh
    INFO: Running SQL query...
    INFO: Got a page of query result with 1 items(s) and request charge of 2.83
    INFO: Item Ids [2]
    INFO: Deleted User 1
    

Sie haben nun Dokumente in Ihrer Anwendung erstellt und können diese aus Ihrer Anwendung abrufen. Spring Data Azure Cosmos DB macht sowohl abgeleitete Abfragemethoden als auch benutzerdefinierte Abfragemethoden verfügbar. Beide Methoden basieren auf der SQL-Sprachabfragefunktion des zugrunde liegenden Azure Cosmos DB Java SDK v4. In dieser Lerneinheit geht es primär um die Ausführung von Spring Data Azure Cosmos DB-Abfragen aus der Anwendung, nicht aus dem Portal.

Zum Testen dieser Abfragen werden die WebCustomer-Dokumente verwendet, die Sie für Ihre Anwendung für Onlinehändler erstellt haben.

Erstellen und Abrufen abgeleiteter Abfragemethoden

Abgeleitete Abfragemethoden sind Spring Data-Repositorymethoden ohne Implementierung. Stattdessen signalisiert der Methodenname Spring Data, dass jeder Methodenaufruf und die zugehörigen Argumente in eine Abfrage der zugrunde liegenden Datenbank übersetzt werden müssen. Ein Beispiel: Wenn Sie findById mit Argumenten aufrufen, interpretiert Spring Data den Namen als „nach ID suchen“ und stellt eine Datenbankabfrage zusammen, die das von den Argumenten angegebene Dokument zurückgibt.

Spring Data Azure Cosmos DB enthält eine Reihe integrierter abgeleiteter Abfrage, wie beispielsweise findById. In diesem Abschnitt soll gezeigt werden, wie Sie neue abgeleitete Abfragemethoden implementieren.

  1. Wir erstellen eine abgeleitete Abfragemethode, die alle Dokumente mit einem bestimmten Wert im Feld firstName abfragt. Navigieren Sie zu ReactWebCustomerRepository.java. Die folgende Methodendeklaration wird angezeigt:

    Flux<WebCustomer> findByFirstName(String firstName);
    

    Diese Repositorymethode informiert Spring Data darüber, dass Sie eine Methode erstellen möchten, die beim Aufruf firstName abfragt. Sie erinnern sich sicher: Die WebCustomer-Klasse beginnt mit einer @Container-Anmerkung, die containerName als WebCustomers angibt. findByFirstName gibt Flux<WebCustomer> zurück. Daher weiß Spring Data, dass WebCustomers abgefragt werden soll, wenn diese Methode aufgerufen wird.

  2. Kopieren Sie den folgenden Code, und fügen Sie ihn vor dem Aufruf von deleteWebCustomerDocument in Ihre run-Methode ein.

    logger.info("Running derived query...");
    Flux<WebCustomer> webCustomers = reactiveWebCustomerRepository.findByFirstName("Max");
    webCustomers.flatMap(webCustomer -> {
        logger.info("- WebCustomer is : {}", webCustomer.getUserId());
        return Mono.empty();
    }).blockLast();
    

    Beachten Sie in diesem Code, dass wir das deklarative Datenfluss-Programmiermodell von Project Reactor erneut verwenden. Dieses Mal verwenden wir es, um Abfrageantwortseiten asynchron zu verarbeiten. Wir zeigen einen asynchronen Ansatz, da es in realen Anwendungsfällen Hunderte oder Tausende von Antworten auf eine Abfrage geben kann. Das Aggregieren von Abfrageantworten kann ein CPU-intensiver Task sein, der von der verbesserten Threadeffizienz der asynchronen Programmierung profitiert.

    Kurz gesagt: Hier ist ein hoher Durchsatz für das Verarbeiten von Abfrageantworten erforderlich bzw. ein hoher Antworten/Sekunde-Wert pro Thread. findByFirstName gibt die Flux<WebCustomer>-Instanz webCustomers zurück. Die Vorgangspipeline innerhalb von .flatMap( ... ).blockLast(); funktioniert asynchron und quasi-parallel zu den Abfrageantworten, die den einzelnen von Flux<WebCustomer> ausgegebenen Ereignissen zugeordnet sind.

  3. Erstellen Sie CosmosSample.java in der IDE, und führen Sie das Programm aus, oder führen Sie das Programm wie folgt im Terminal aus:

    mvn clean package
    mvn spring-boot:run
    

    Die Ausgabe im Terminal sollte ungefähr wie folgt aussehen:

    INFO: - WebCustomer is : maxaxam
    

Erstellen und Aufrufen benutzerdefinierter Abfragemethoden

Benutzerdefinierte Abfragemethoden sind Spring Data-Repositorymethoden mit einer @Query-Anmerkung, die eine Abfragezeichenfolge angibt. Die Abfragezeichenfolge enthält Platzhalter für die Methodenargumente. Diesmal hat der Methodenname keine Auswirkungen darauf, welche Abfrage ausgeführt wird. Die @Query-Anmerkung signalisiert Spring Data, dass eine SQL-Sprachabfrage an die zugrunde liegende Datenbank ausgegeben werden soll, nachdem die Argumentplatzhalter mit den Werten der Methodenargumente aufgefüllt wurden.

  1. Wir erstellen eine benutzerdefinierte Abfragemethode, die alle Dokumente mit einem bestimmten Wert im Feld lastName abfragt. Navigieren Sie zu ReactWebCustomerRepository.java. Die folgende Methodendeklaration wird angezeigt:

    @Query(value = "SELECT * FROM User WHERE User.lastName = @lastName")
    Flux<WebCustomer> findByLastName(@Param("lastName") String lastName);
    

    Diese Repositorymethode informiert Spring Data darüber, dass Sie eine Methode erstellen möchten, die beim Aufruf lastName abfragt. Das Argument lastName wird durch den Platzhalter @lastName ersetzt.

  2. Kopieren Sie den folgenden Code, und fügen Sie ihn nach dem abgeleiteten Abfragecode in Ihre run-Methode ein.

    logger.info("Running custom query...");
    webCustomers = reactiveWebCustomerRepository.findByLastName("Axam");
    webCustomers.flatMap(webCustomer -> {
        logger.info("- WebCustomer is : {}", webCustomer.getUserId());
        return Mono.empty();
    }).blockLast();
    
  3. Erstellen Sie CosmosSample.java in der IDE, und führen Sie das Programm aus, oder führen Sie das Programm wie folgt im Terminal aus:

    mvn clean package
    mvn spring-boot:run
    

    Die Ausgabe im Terminal sollte ungefähr wie folgt aussehen:

    INFO: Running derived query...
    INFO: - WebCustomer is : maxaxam
    INFO: Running custom query...
    INFO: - WebCustomer is : maxaxam    
    

In dieser Einheit haben Sie abgeleitete und benutzerdefinierte Abfragen kennengelernt. Anschließend haben Sie Ihrer Anwendung beide Abfragetypen hinzugefügt, um Benutzerdatensätze abzurufen.