diff --git a/README.md b/README.md index a3087b3..64b575d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ You may want to use this playground to: * Learn more about `Elastic.Clients.Elasticsearch` and `NEST` clients * You want to migrate your existing code from `NEST` to `Elastic.Clients.Elasticsearch`. -> See [playground.ipynb](./playground.ipynb) to get started. +> See [playground.ipynb](./src/nest-vs-elasticsearch/playground.ipynb) to get started. ![setup-elastic-infra](./assets/setup-elastic-infra.png) @@ -47,4 +47,6 @@ jupyter-lab * Elasticsearch.NET - * NEST + Elasticsearch.NET in one doc - * .NET Interactive | Samples - -* .NET Interactive - \ No newline at end of file +* .NET Interactive - +* Elasticsearch Labs +* \ No newline at end of file diff --git a/src/get-connection-string.ipynb b/src/_infra/get-connection-string.ipynb similarity index 67% rename from src/get-connection-string.ipynb rename to src/_infra/get-connection-string.ipynb index 94ae817..8db6f44 100644 --- a/src/get-connection-string.ipynb +++ b/src/_infra/get-connection-string.ipynb @@ -13,11 +13,25 @@ }, "outputs": [], "source": [ - "#!import ./common.ipynb\n", - "\n", + "#r \"nuget: dotenv.net\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ "using dotenv.net;\n", "\n", - "var variables = DotEnv.Read(new DotEnvOptions(envFilePaths: new[] {\"../.env\"}));\n", + "var variables = DotEnv.Read(new DotEnvOptions(envFilePaths: new[] {\"../../.env\"}));\n", "\n", "if (!variables.TryGetValue(\"PLAYGROUND_CONNECTION_STRING\", out var connectionStringInput)\n", " || string.IsNullOrEmpty(connectionStringInput))\n", @@ -27,6 +41,20 @@ "\n", "var connectionString = new Uri(connectionStringInput);" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/src/setup-elastic-infrastructure.ipynb b/src/_infra/setup-elastic-infrastructure.ipynb similarity index 93% rename from src/setup-elastic-infrastructure.ipynb rename to src/_infra/setup-elastic-infrastructure.ipynb index 9004ead..6890fc5 100644 --- a/src/setup-elastic-infrastructure.ipynb +++ b/src/_infra/setup-elastic-infrastructure.ipynb @@ -13,7 +13,7 @@ }, "outputs": [], "source": [ - "#!import ./common.ipynb" + "#r \"nuget: Testcontainers.Elasticsearch\"" ] }, { @@ -39,9 +39,6 @@ }, "outputs": [], "source": [ - "using Nest;\n", - "using Elastic.Clients.Elasticsearch;\n", - "using Elastic.Transport;\n", "using Testcontainers.Elasticsearch;\n", "\n", "var elasticsearchContainer = new ElasticsearchBuilder()\n", diff --git a/src/elasticsearch-getting-started/00-quickstart.ipynb b/src/elasticsearch-getting-started/00-quickstart.ipynb new file mode 100644 index 0000000..819aafb --- /dev/null +++ b/src/elasticsearch-getting-started/00-quickstart.ipynb @@ -0,0 +1,258 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget: Elastic.Clients.Elasticsearch\"\n", + "#r \"nuget: System.Net.Http.Json\"\n", + "#!import ./Utils.cs\n", + "#!import ../_infra/get-connection-string.ipynb\n", + "\n", + "using Elastic.Transport;\n", + "using Elastic.Clients.Elasticsearch;\n", + "using Elastic.Transport.Products.Elasticsearch;\n", + "\n", + "var elasticSettings = new ElasticsearchClientSettings(connectionString)\n", + " .DisableDirectStreaming()\n", + " .ServerCertificateValidationCallback(CertificateValidations.AllowAll);\n", + "\n", + "var client = new ElasticsearchClient(elasticSettings);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the Client\n", + "\n", + "Before you continue, confirm that the client has connected with this test.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var info = await client.InfoAsync();\n", + "\n", + "display(info);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Index some test data\n", + "Our client is set up and connected to our Elastic deployment. Now we need some data to test out the basics of Elasticsearch queries. We'll use a small index of books with the following fields" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "using System.Text.Json.Serialization;\n", + "\n", + "public class Book\n", + "{\n", + " [JsonPropertyName(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [JsonPropertyName(\"summary\")]\n", + " public string Summary { get; set; }\n", + "\n", + " [JsonPropertyName(\"publish_date\")]\n", + " public DateTimeOffset PublishDate { get; set; }\n", + "\n", + " [JsonPropertyName(\"num_reviews\")]\n", + " public int NumReviews { get; set; }\n", + "\n", + " [JsonPropertyName(\"publisher\")]\n", + " public string Publisher { get; set; }\n", + "\n", + "\n", + " public object? TitleVector { get; set; }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "using Elastic.Clients.Elasticsearch;\n", + "using Elastic.Clients.Elasticsearch.IndexManagement;\n", + "using Elastic.Clients.Elasticsearch.Mapping;\n", + "\n", + "const string BookIndex = \"book_index\";\n", + "var indexDescriptor = new CreateIndexRequestDescriptor(BookIndex)\n", + " .Mappings(m => m\n", + " .Properties(pp => pp\n", + " .Text(p => p.Title)\n", + " .DenseVector(\n", + " Infer.Property(p => p.TitleVector),\n", + " d => d.Dims(384).Index(true).Similarity(DenseVectorSimilarity.Cosine))\n", + " .Text(p => p.Summary)\n", + " .Date(p => p.PublishDate)\n", + " .IntegerNumber(p => p.NumReviews)\n", + " .Keyword(p => p.Publisher)\n", + " )\n", + " );" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var indexResponse = await client.Indices.CreateAsync(indexDescriptor);\n", + "\n", + "display(indexResponse);\n", + "ToJson(DumpGetRequest(indexResponse.DebugInformation)).Display();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "using System.Net.Http;\n", + "using System.Net.Http.Json;\n", + "\n", + "var http = new HttpClient();\n", + "var url = \"https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/notebooks/search/data.json\";\n", + "var books = await http.GetFromJsonAsync(url);\n", + "\n", + "display(books);\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var bulkResponse = await client.BulkAsync(BookIndex, d => d\n", + " .IndexMany(books, (bd, b) => bd.Index(BookIndex).));\n", + "\n", + "display(DumpGetRequest(bulkResponse));" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var searchResponse = await client.SearchAsync(s => \n", + " s \n", + " .Index(BookIndex)\n", + " .Query(q => q.Match(d => d.Field(f => f.Title).Query(\"JavaScript\")))\n", + ");\n", + "\n", + "DumpGetRequest(searchResponse).Display();\n", + "\n", + "searchResponse.Display();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "languageName": "csharp", + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/elasticsearch-getting-started/Utils.cs b/src/elasticsearch-getting-started/Utils.cs new file mode 100644 index 0000000..697eb78 --- /dev/null +++ b/src/elasticsearch-getting-started/Utils.cs @@ -0,0 +1,64 @@ +using System.Text.Json; +using System.IO; +using Elastic.Clients.Elasticsearch; +using Elastic.Transport.Products.Elasticsearch; + + +static object DumpGetRequest(ElasticsearchResponse response) +{ + return DumpGetRequest(response.DebugInformation); +} + +static object DumpGetRequest(string debugInformation) +{ + return TryParsePayload(GetRequestFromDebugInformation(debugInformation)); +} + +static object TryParsePayload(string payload) +{ + try + { + return JsonDocument.Parse(payload.Trim()); + } + catch + { + return payload; + } +} + +static string ToJson(object paylod) +{ + return prettyJson(System.Text.Json.JsonSerializer.Serialize(paylod)); + + static string prettyJson(string json) + { + try + { + var jsonDocument = JsonDocument.Parse(json); + var options = new JsonSerializerOptions { WriteIndented = true }; + string prettyJson = JsonSerializer.Serialize(jsonDocument, options); + + return prettyJson; + } + catch (Exception) + { + return json; + } + } +} + +static string GetRequestFromDebugInformation(string paylod) +{ + var request = paylod + .Split(new[] { "# Request:" }, StringSplitOptions.None)[1] + .Split(new[] { "# Response:" }, StringSplitOptions.None)[0]; + + return request; +} + +static string GetResponseFromDebugInformation(string paylod) +{ + var response = paylod.Split(new[] { "# Response:" }, StringSplitOptions.None)[1]; + + return response; +} diff --git a/src/elasticsearch-getting-started/data.json b/src/elasticsearch-getting-started/data.json new file mode 100644 index 0000000..ebc8168 --- /dev/null +++ b/src/elasticsearch-getting-started/data.json @@ -0,0 +1,87 @@ +[ + { + "title": "The Pragmatic Programmer: Your Journey to Mastery", + "authors": ["andrew hunt", "david thomas"], + "summary": "A guide to pragmatic programming for software engineers and developers", + "publish_date": "2019-10-29", + "num_reviews": 30, + "publisher": "addison-wesley" + }, + { + "title": "Python Crash Course", + "authors": ["eric matthes"], + "summary": "A fast-paced, no-nonsense guide to programming in Python", + "publish_date": "2019-05-03", + "num_reviews": 42, + "publisher": "no starch press" + }, + { + "title": "Artificial Intelligence: A Modern Approach", + "authors": ["stuart russell", "peter norvig"], + "summary": "Comprehensive introduction to the theory and practice of artificial intelligence", + "publish_date": "2020-04-06", + "num_reviews": 39, + "publisher": "pearson" + }, + { + "title": "Clean Code: A Handbook of Agile Software Craftsmanship", + "authors": ["robert c. martin"], + "summary": "A guide to writing code that is easy to read, understand and maintain", + "publish_date": "2008-08-11", + "num_reviews": 55, + "publisher": "prentice hall" + }, + { + "title": "You Don't Know JS: Up & Going", + "authors": ["kyle simpson"], + "summary": "Introduction to JavaScript and programming as a whole", + "publish_date": "2015-03-27", + "num_reviews": 36, + "publisher": "oreilly" + }, + { + "title": "Eloquent JavaScript", + "authors": ["marijn haverbeke"], + "summary": "A modern introduction to programming", + "publish_date": "2018-12-04", + "num_reviews": 38, + "publisher": "no starch press" + }, + { + "title": "Design Patterns: Elements of Reusable Object-Oriented Software", + "authors": [ + "erich gamma", + "richard helm", + "ralph johnson", + "john vlissides" + ], + "summary": "Guide to design patterns that can be used in any object-oriented language", + "publish_date": "1994-10-31", + "num_reviews": 45, + "publisher": "addison-wesley" + }, + { + "title": "The Clean Coder: A Code of Conduct for Professional Programmers", + "authors": ["robert c. martin"], + "summary": "A guide to professional conduct in the field of software engineering", + "publish_date": "2011-05-13", + "num_reviews": 20, + "publisher": "prentice hall" + }, + { + "title": "JavaScript: The Good Parts", + "authors": ["douglas crockford"], + "summary": "A deep dive into the parts of JavaScript that are essential to writing maintainable code", + "publish_date": "2008-05-15", + "num_reviews": 51, + "publisher": "oreilly" + }, + { + "title": "Introduction to the Theory of Computation", + "authors": ["michael sipser"], + "summary": "Introduction to the theory of computation and complexity theory", + "publish_date": "2012-06-27", + "num_reviews": 33, + "publisher": "cengage learning" + } +] diff --git a/src/elasticsearch-getting-started/setup-client.ipynb b/src/elasticsearch-getting-started/setup-client.ipynb new file mode 100644 index 0000000..bfd1506 --- /dev/null +++ b/src/elasticsearch-getting-started/setup-client.ipynb @@ -0,0 +1,82 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget: Elastic.Clients.Elasticsearch\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#!import ../_infra/get-connection-string.ipynb\n", + "\n", + "using Elastic.Transport;\n", + "using Elastic.Clients.Elasticsearch;\n", + "using Elastic.Transport.Products.Elasticsearch;\n", + "\n", + "var connectionString = new Uri(connectionStringInput);\n", + "var elasticSettings = new ElasticsearchClientSettings(connectionString)\n", + " .DisableDirectStreaming()\n", + " .ServerCertificateValidationCallback(CertificateValidations.AllowAll);\n", + "\n", + "var client = new ElasticsearchClient(elasticSettings);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "languageName": "csharp", + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/Utils.cs b/src/nest-vs-elasticsearch/Utils.cs similarity index 100% rename from src/Utils.cs rename to src/nest-vs-elasticsearch/Utils.cs diff --git a/src/common.ipynb b/src/nest-vs-elasticsearch/common.ipynb similarity index 100% rename from src/common.ipynb rename to src/nest-vs-elasticsearch/common.ipynb diff --git a/playground.ipynb b/src/nest-vs-elasticsearch/playground.ipynb similarity index 81% rename from playground.ipynb rename to src/nest-vs-elasticsearch/playground.ipynb index 237d99d..885d2fb 100644 --- a/playground.ipynb +++ b/src/nest-vs-elasticsearch/playground.ipynb @@ -10,7 +10,7 @@ "\n", "## Prerequisites\n", "\n", - "* Get a connection string to your Elasticsearch instance, you may want to use the local installation, see [setup-elastic-infrastructure.ipynb](./src/setup-elastic-infrastructure.ipynb)\n", + "* Get a connection string to your Elasticsearch instance, you may want to use the local installation, see [setup-elastic-infrastructure.ipynb](./setup-elastic-infrastructure.ipynb)\n", "\n", "## Scope\n", "\n", @@ -28,7 +28,7 @@ "source": [ "## Index Management\n", "\n", - "See the [setup-nest.ipynb](./src/setup-nest.ipynb) notebook for details.\n", + "See the [setup-nest.ipynb](./setup-nest.ipynb) notebook for details.\n", "\n", "### Breaking changes:\n", "\n", @@ -41,7 +41,7 @@ "source": [ "## Searching for data\n", "\n", - "See the [search.ipynb](./src/search.ipynb) notebook for details." + "See the [search.ipynb](./search.ipynb) notebook for details." ] }, { @@ -50,10 +50,15 @@ "source": [ "## Scrolling\n", "\n", - "See the [scroll.ipynb](./src/scroll.ipynb) notebook for details.\n", + "See the [scroll.ipynb](./scroll.ipynb) notebook for details.\n", "\n", "💡 It is recommended to use the `SearchAsync` API to traverse the index." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] } ], "metadata": { diff --git a/src/scroll.ipynb b/src/nest-vs-elasticsearch/scroll.ipynb similarity index 100% rename from src/scroll.ipynb rename to src/nest-vs-elasticsearch/scroll.ipynb diff --git a/src/search.ipynb b/src/nest-vs-elasticsearch/search.ipynb similarity index 81% rename from src/search.ipynb rename to src/nest-vs-elasticsearch/search.ipynb index 54f28c3..e7002fe 100644 --- a/src/search.ipynb +++ b/src/nest-vs-elasticsearch/search.ipynb @@ -11,17 +11,7 @@ "kernelName": "csharp" } }, - "outputs": [ - { - "data": { - "text/html": [ - "
Installed Packages
  • Bogus, 35.6.1
  • dotenv.net, 3.2.0
  • Elastic.Clients.Elasticsearch, 8.15.6
  • Microsoft.Data.Analysis, 0.21.1
  • NEST, 7.17.5
  • System.Linq.Async, 6.0.1
  • Testcontainers.Elasticsearch, 3.10.0
  • XUnit, 2.9.0
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "const string PostsIndex = \"posts\";\n", "\n", diff --git a/src/setup-clients.ipynb b/src/nest-vs-elasticsearch/setup-clients.ipynb similarity index 94% rename from src/setup-clients.ipynb rename to src/nest-vs-elasticsearch/setup-clients.ipynb index 16e14c4..4ee3521 100644 --- a/src/setup-clients.ipynb +++ b/src/nest-vs-elasticsearch/setup-clients.ipynb @@ -13,7 +13,8 @@ }, "outputs": [], "source": [ - "#!import ./get-connection-string.ipynb\n", + "#!import ../_infra/get-connection-string.ipynb\n", + "#!import ./common.ipynb\n", "\n", "using Nest;\n", "using Elastic.Transport;\n", diff --git a/src/nest-vs-elasticsearch/setup-elastic-net.ipynb b/src/nest-vs-elasticsearch/setup-elastic-net.ipynb new file mode 100644 index 0000000..ad2d14a --- /dev/null +++ b/src/nest-vs-elasticsearch/setup-elastic-net.ipynb @@ -0,0 +1,240 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#!import ./get-connection-string.ipynb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Index Management" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create Index" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "using Elastic.Clients.Elasticsearch.IndexManagement;\n", + "using Elastic.Clients.Elasticsearch;\n", + "using Elastic.Transport;\n", + "\n", + "var indexName = Elastic.Clients.Elasticsearch.IndexName.From();\n", + "\n", + "var elasticSettings = new ElasticsearchClientSettings(connectionString)\n", + " .DisableDirectStreaming()\n", + " .ServerCertificateValidationCallback(CertificateValidations.AllowAll);\n", + "\n", + "elasticSettings.DefaultMappingFor(s => s.IndexName(\"posts\"));\n", + "\n", + "var client = new ElasticsearchClient(elasticSettings);\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "using Elastic.Clients.Elasticsearch.Mapping;\n", + "using Infer = Elastic.Clients.Elasticsearch.Infer;\n", + "\n", + "var descriptor = new Elastic.Clients.Elasticsearch.IndexManagement.CreateIndexRequestDescriptor(indexName)\n", + " .Mappings(md => md.Properties(ApplyBlogPostMapping));\n", + "\n", + "var createResponse = await client.Indices.CreateAsync(descriptor);\n", + "DumpResponse(createResponse);\n", + "\n", + "void ApplyBlogPostMapping(\n", + " Elastic.Clients.Elasticsearch.Mapping.PropertiesDescriptor descriptor)\n", + "{\n", + " descriptor\n", + " .Keyword(p => p.Id)\n", + " .Text(p => p.Title)\n", + " .Text(p => p.Description)\n", + " .Date(p => p.CreatedAt)\n", + " .Boolean(p => p.IsPublished)\n", + " .Object(p => p.Author, d => d.Properties(\n", + " pp => pp\n", + " .Keyword(p => p.Author.Id)\n", + " .Text(p => p.Author.Name)\n", + " .Text(p => p.Author.Email)\n", + " )\n", + " )\n", + " .Object(p => p.Likes, d => d.Properties(\n", + " pp => pp\n", + " .Keyword(Infer.Property(p => p.Id))\n", + " .Keyword(Infer.Property(p => p.PostId))\n", + " .Text(Infer.Property(p => p.AuthorId))\n", + " .Date(Infer.Property(p => p.CreatedAt))\n", + " )\n", + " );\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Delete Index" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var deleteResponse = await client.Indices.DeleteAsync();\n", + "\n", + "DumpResponse(deleteResponse);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Seed Data" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "Bogus.Randomizer.Seed = new Random(123);\n", + "\n", + "var faker = new Bogus.Faker()\n", + " .RuleFor(p => p.Id, f => f.Random.Number(int.MaxValue))\n", + " .RuleFor(p => p.Title, f => f.Commerce.ProductName())\n", + " .RuleFor(p => p.Description, f => f.Lorem.Paragraph())\n", + " .RuleFor(p => p.Author, f => f.Name.FullName())\n", + " .RuleFor(p => p.CreatedAt, f => f.Date.Past());\n", + "\n", + "var posts = faker.Generate(1000);" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var bulkResponse = await _client.BulkAsync(b => b\n", + " .Index(PostsIndex)\n", + " .IndexMany(posts)\n", + ");\n", + "\n", + "display(bulkResponse.Errors);" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "DumpResponse(bulkResponse);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "languageName": "csharp", + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/setup-nest.ipynb b/src/nest-vs-elasticsearch/setup-nest.ipynb similarity index 100% rename from src/setup-nest.ipynb rename to src/nest-vs-elasticsearch/setup-nest.ipynb diff --git a/src/setup-elastic-net.ipynb b/src/setup-elastic-net.ipynb deleted file mode 100644 index be95746..0000000 --- a/src/setup-elastic-net.ipynb +++ /dev/null @@ -1,351 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "#!import ./get-connection-string.ipynb" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Index Management" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create Index" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "using Elastic.Clients.Elasticsearch.IndexManagement;\n", - "using Elastic.Clients.Elasticsearch;\n", - "using Elastic.Transport;\n", - "\n", - "var indexName = Elastic.Clients.Elasticsearch.IndexName.From();\n", - "\n", - "var elasticSettings = new ElasticsearchClientSettings(connectionString)\n", - " .DisableDirectStreaming()\n", - " .ServerCertificateValidationCallback(CertificateValidations.AllowAll);\n", - "\n", - "elasticSettings.DefaultMappingFor(s => s.IndexName(\"posts\"));\n", - "\n", - "var client = new ElasticsearchClient(elasticSettings);\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Valid Elasticsearch response built from a successful (200) low level call on PUT: /posts\r\n", - "\r\n", - "# Audit trail of this API call:\r\n", - " - [1] HealthyResponse: Node: https://elastic:redacted@127.0.0.1:9200/ Took: 00:00:00.3645419\r\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "⚙️❔Request:" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{"mappings":{"properties":{"id":{"type":"keyword"},"title":{"type":"text"},"description":{"type":"text"},"createdAt":{"type":"date"},"isPublished":{"type":"boolean"},"author":{"properties":{"id":{"type":"keyword"},"name":{"type":"text"},"email":{"type":"text"}},"type":"object"},"likes":{"properties":{"id":{"type":"keyword"},"postId":{"type":"keyword"},"authorId":{"type":"text"},"createdAt":{"type":"date"}},"type":"object"}}}}
mappings
{"properties":{"id":{"type":"keyword"},"title":{"type":"text"},"description":{"type":"text"},"createdAt":{"type":"date"},"isPublished":{"type":"boolean"},"author":{"properties":{"id":{"type":"keyword"},"name":{"type":"text"},"email":{"type":"text"}},"type":"object"},"likes":{"properties":{"id":{"type":"keyword"},"postId":{"type":"keyword"},"authorId":{"type":"text"},"createdAt":{"type":"date"}},"type":"object"}}}
properties
{"id":{"type":"keyword"},"title":{"type":"text"},"description":{"type":"text"},"createdAt":{"type":"date"},"isPublished":{"type":"boolean"},"author":{"properties":{"id":{"type":"keyword"},"name":{"type":"text"},"email":{"type":"text"}},"type":"object"},"likes":{"properties":{"id":{"type":"keyword"},"postId":{"type":"keyword"},"authorId":{"type":"text"},"createdAt":{"type":"date"}},"type":"object"}}
id
{"type":"keyword"}
type"keyword"
title
{"type":"text"}
type"text"
description
{"type":"text"}
type"text"
createdAt
{"type":"date"}
type"date"
isPublished
{"type":"boolean"}
type"boolean"
author
{"properties":{"id":{"type":"keyword"},"name":{"type":"text"},"email":{"type":"text"}},"type":"object"}
properties
{"id":{"type":"keyword"},"name":{"type":"text"},"email":{"type":"text"}}
id{\"type\":\"keyword\"}
name{\"type\":\"text\"}
email{\"type\":\"text\"}
type"object"
likes
{"properties":{"id":{"type":"keyword"},"postId":{"type":"keyword"},"authorId":{"type":"text"},"createdAt":{"type":"date"}},"type":"object"}
properties
{"id":{"type":"keyword"},"postId":{"type":"keyword"},"authorId":{"type":"text"},"createdAt":{"type":"date"}}
id{\"type\":\"keyword\"}
postId{\"type\":\"keyword\"}
authorId{\"type\":\"text\"}
createdAt{\"type\":\"date\"}
type"object"
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "⚙️🟰Response:" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{"acknowledged":true,"shards_acknowledged":true,"index":"posts"}
acknowledgedtrue
shards_acknowledgedtrue
index"posts"
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "using Elastic.Clients.Elasticsearch.Mapping;\n", - "using Infer = Elastic.Clients.Elasticsearch.Infer;\n", - "\n", - "var descriptor = new Elastic.Clients.Elasticsearch.IndexManagement.CreateIndexRequestDescriptor(indexName)\n", - " .Mappings(md => md.Properties(ApplyBlogPostMapping));\n", - "\n", - "var createResponse = await client.Indices.CreateAsync(descriptor);\n", - "DumpResponse(createResponse);\n", - "\n", - "void ApplyBlogPostMapping(\n", - " Elastic.Clients.Elasticsearch.Mapping.PropertiesDescriptor descriptor)\n", - "{\n", - " descriptor\n", - " .Keyword(p => p.Id)\n", - " .Text(p => p.Title)\n", - " .Text(p => p.Description)\n", - " .Date(p => p.CreatedAt)\n", - " .Boolean(p => p.IsPublished)\n", - " .Object(p => p.Author, d => d.Properties(\n", - " pp => pp\n", - " .Keyword(p => p.Author.Id)\n", - " .Text(p => p.Author.Name)\n", - " .Text(p => p.Author.Email)\n", - " )\n", - " )\n", - " .Object(p => p.Likes, d => d.Properties(\n", - " pp => pp\n", - " .Keyword(Infer.Property(p => p.Id))\n", - " .Keyword(Infer.Property(p => p.PostId))\n", - " .Text(Infer.Property(p => p.AuthorId))\n", - " .Date(Infer.Property(p => p.CreatedAt))\n", - " )\n", - " );\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Delete Index" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "var deleteResponse = await client.Indices.DeleteAsync();\n", - "\n", - "DumpResponse(deleteResponse);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Seed Data" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "Bogus.Randomizer.Seed = new Random(123);\n", - "\n", - "var faker = new Bogus.Faker()\n", - " .RuleFor(p => p.Id, f => f.Random.Number(int.MaxValue))\n", - " .RuleFor(p => p.Title, f => f.Commerce.ProductName())\n", - " .RuleFor(p => p.Description, f => f.Lorem.Paragraph())\n", - " .RuleFor(p => p.Author, f => f.Name.FullName())\n", - " .RuleFor(p => p.CreatedAt, f => f.Date.Past());\n", - "\n", - "var posts = faker.Generate(1000);" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "var bulkResponse = await _client.BulkAsync(b => b\n", - " .Index(PostsIndex)\n", - " .IndexMany(posts)\n", - ");\n", - "\n", - "display(bulkResponse.Errors);" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [ - "DumpResponse(bulkResponse);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".NET (C#)", - "language": "C#", - "name": ".net-csharp" - }, - "polyglot_notebook": { - "kernelInfo": { - "defaultKernelName": "csharp", - "items": [ - { - "aliases": [], - "languageName": "csharp", - "name": "csharp" - } - ] - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}