diff --git a/java/105_aggregation_pipeline_explain.ipynb b/java/105_aggregation_pipeline_explain.ipynb new file mode 100644 index 0000000..494dc10 --- /dev/null +++ b/java/105_aggregation_pipeline_explain.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9d2c1c5d", + "metadata": {}, + "source": [ + "[![Aggregation Pipeline Lab](https://img.shields.io/badge/Aggregation%20Pipeline%20Lab-darkgreen)](https://mongodb-developer.github.io/aggregation-pipeline-lab/)" + ] + }, + { + "cell_type": "markdown", + "id": "3b936925-e295-489a-b508-2b99c0160217", + "metadata": {}, + "source": [ + "# Aggregation Pipeline: explain()\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "4762f21c", + "metadata": {}, + "source": [ + "## What does `explain()` do?\n", + "\n", + "`explain()` shows how MongoDB executes a query or aggregation pipeline. It is useful for understanding whether MongoDB is using an index and how much work the query performs.\n", + "\n", + "In this example, we will focus on two important fields:\n", + "\n", + "- `Index usage`: shows whether the query uses an index\n", + "- `Execution time (ms)`: shows how long the query took to run\n", + "\n", + "We will run the same aggregation before and after creating an index, then compare the results." + ] + }, + { + "cell_type": "markdown", + "id": "dependent-boundary", + "metadata": {}, + "source": [ + "## Startup code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66ef28c4-f86b-4576-839e-100a7ae022c7", + "metadata": {}, + "outputs": [], + "source": [ + "// Import the MongoDB Driver using Maven\n", + "%maven org.mongodb:mongodb-driver-sync:5.5.1\n", + "%maven org.slf4j:slf4j-simple:1.7.36\n", + "\n", + "import com.mongodb.ExplainVerbosity;\n", + "import com.mongodb.client.AggregateIterable;\n", + "import com.mongodb.client.MongoClient;\n", + "import com.mongodb.client.MongoClients;\n", + "import com.mongodb.client.MongoCollection;\n", + "import com.mongodb.client.MongoDatabase;\n", + "import com.mongodb.client.model.Indexes;\n", + "import org.bson.Document;\n", + "\n", + "import java.util.List;\n", + "\n", + "import static com.mongodb.client.model.Aggregates.match;\n", + "import static com.mongodb.client.model.Filters.and;\n", + "import static com.mongodb.client.model.Filters.eq;\n", + "\n", + "// Configure SLF4J Simple Logger to suppress MongoDB driver logs in the notebook output.\n", + "System.setProperty(\"org.slf4j.simpleLogger.defaultLogLevel\", \"off\");\n", + "System.setProperty(\"org.slf4j.simpleLogger.log.org.mongodb.driver\", \"off\");\n", + "\n", + "// Set your connection String\n", + "String connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "// Define our database and collection.\n", + "MongoClient mongoClient = null;\n", + "try {\n", + " mongoClient = MongoClients.create(connectionString);\n", + "} catch (Exception e) {\n", + " System.out.println(e);\n", + "}\n", + "\n", + "MongoDatabase library = mongoClient.getDatabase(\"library\");\n", + "MongoCollection books = library.getCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "d98078a6", + "metadata": {}, + "source": [ + "## Before creating the index\n", + "\n", + "First, we run the aggregation with `explain()` to check the execution time and whether MongoDB uses an index." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab8508aa", + "metadata": {}, + "outputs": [], + "source": [ + "var filter = and(\n", + " eq(\"title\", \"Collins Gem Italian Dictionary, 5e\"),\n", + " eq(\"year\", 2001)\n", + ");\n", + "\n", + "var explainResult = books.aggregate(\n", + " List.of(match(filter))\n", + ").explain(ExplainVerbosity.EXECUTION_STATS);\n", + "\n", + "System.out.println(\"Execution time (ms): \" +\n", + " explainResult.get(\"executionStats\", Document.class).get(\"executionTimeMillis\"));\n", + "\n", + "System.out.println(\"Index usage: \" +\n", + " explainResult.get(\"queryPlanner\", Document.class)\n", + " .get(\"winningPlan\", Document.class)\n", + " .toJson()\n", + " .contains(\"IXSCAN\"));" + ] + }, + { + "cell_type": "markdown", + "id": "c15e4530", + "metadata": {}, + "source": [ + "## Create an index\n", + "\n", + "Now, we create an index on the fields used in the filter and list the indexes before and after the operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31a0c996", + "metadata": {}, + "outputs": [], + "source": [ + "System.out.println(\"## Listing indexes\");\n", + "books.listIndexes().forEach(System.out::println);\n", + "\n", + "System.out.println(\"Creating new index...\");\n", + "books.createIndex(Indexes.ascending(\"title\", \"year\"));\n", + "\n", + "System.out.println(\"## Listing indexes\");\n", + "books.listIndexes().forEach(System.out::println);" + ] + }, + { + "cell_type": "markdown", + "id": "7604272c", + "metadata": {}, + "source": [ + "## After creating the index\n", + "\n", + "Finally, we run the same aggregation again and compare the execution time and index usage." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aea847d7", + "metadata": {}, + "outputs": [], + "source": [ + "var explainResult = books.aggregate(\n", + " List.of(match(filter))\n", + ").explain(ExplainVerbosity.EXECUTION_STATS);\n", + "\n", + "System.out.println(\"Execution time (ms): \" +\n", + " explainResult.get(\"executionStats\", Document.class).get(\"executionTimeMillis\"));\n", + "\n", + "System.out.println(\"Index usage: \" +\n", + " explainResult.get(\"queryPlanner\", Document.class)\n", + " .get(\"winningPlan\", Document.class)\n", + " .toJson()\n", + " .contains(\"IXSCAN\"));" + ] + }, + { + "cell_type": "markdown", + "id": "f756ad70", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "With `explain()`, we can compare how MongoDB executes the same aggregation before and after creating an index. For basic performance analysis, two useful things to check are index usage and execution time." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Java", + "language": "java", + "name": "java" + }, + "language_info": { + "codemirror_mode": "java", + "file_extension": ".jshell", + "mimetype": "text/x-java-source", + "name": "java", + "pygments_lexer": "java", + "version": "21.0.5+11-LTS" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/java/105_aggregation_pipeline_merge.ipynb b/java/106_aggregation_pipeline_merge.ipynb similarity index 100% rename from java/105_aggregation_pipeline_merge.ipynb rename to java/106_aggregation_pipeline_merge.ipynb