From 7634abf68dc643d162491de8681b3196bed2a37c Mon Sep 17 00:00:00 2001 From: Anshul Sharma Date: Thu, 11 May 2023 11:06:34 +0800 Subject: [PATCH] kusto vector sample added --- ...ted_with_kusto_and_openai_embeddings.ipynb | 1 + examples/vector_databases/kusto/README.md | 34 ++++++++++++++++++ .../kusto/images/kusto_vector_db.png | Bin 0 -> 64243 bytes .../images/semantic_search_user_flow.png | Bin 0 -> 34171 bytes .../kusto/images/wiki_embeddings.png | Bin 0 -> 61727 bytes 5 files changed, 35 insertions(+) create mode 100644 examples/vector_databases/kusto/Getting_started_with_kusto_and_openai_embeddings.ipynb create mode 100644 examples/vector_databases/kusto/README.md create mode 100644 examples/vector_databases/kusto/images/kusto_vector_db.png create mode 100644 examples/vector_databases/kusto/images/semantic_search_user_flow.png create mode 100644 examples/vector_databases/kusto/images/wiki_embeddings.png diff --git a/examples/vector_databases/kusto/Getting_started_with_kusto_and_openai_embeddings.ipynb b/examples/vector_databases/kusto/Getting_started_with_kusto_and_openai_embeddings.ipynb new file mode 100644 index 00000000..d69a226c --- /dev/null +++ b/examples/vector_databases/kusto/Getting_started_with_kusto_and_openai_embeddings.ipynb @@ -0,0 +1 @@ +{"cells":[{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":[]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["# Kusto as a Vector database for AI embeddings"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["This Notebook provides step by step instuctions on using Azure Data Explorer (Kusto) as a vector database with OpenAI embeddings. "]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["This notebook presents an end-to-end process of:\n","\n","1. Using precomputed embeddings created by OpenAI API.\n","2. Storing the embeddings in Kusto.\n","3. Converting raw text query to an embedding with OpenAI API.\n","4. Using Kusto to perform cosine similarity search in the stored embeddings\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["### Prerequisites"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["For the purposes of this exercise we need to prepare a couple of things:\n","\n","1. Azure Data Explorer(Kusto) server instance. https://azure.microsoft.com/en-us/products/data-explorer\n","3. Azure OpenAI credentials or OpenAI API key."]},{"cell_type":"code","execution_count":2,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:24:58.8253972Z","execution_start_time":"2023-05-10T09:24:58.8250545Z","livy_statement_state":"available","parent_msg_id":"affb2f05-b242-4152-99b2-f30e3f854c21","queued_time":"2023-05-10T09:24:43.3953963Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":-1},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, -1, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{},"execution_count":2,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Collecting wget\n"," Downloading wget-3.2.zip (10 kB)\n"," Preparing metadata (setup.py) ... \u001b[?25ldone\n","\u001b[?25hBuilding wheels for collected packages: wget\n"," Building wheel for wget (setup.py) ... \u001b[?25l-\b \bdone\n","\u001b[?25h Created wheel for wget: filename=wget-3.2-py3-none-any.whl size=9657 sha256=10fd8aa1d20fd49c36389dc888acc721d0578c5a0635fc9fc5dc642c0f49522e\n"," Stored in directory: /home/trusted-service-user/.cache/pip/wheels/8b/f1/7f/5c94f0a7a505ca1c81cd1d9208ae2064675d97582078e6c769\n","Successfully built wget\n","Installing collected packages: wget\n","Successfully installed wget-3.2\n","\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.1.2\u001b[0m\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49m/nfs4/pyenv-27214bb4-edfd-4fdd-b888-8a99075a1416/bin/python -m pip install --upgrade pip\u001b[0m\n","Note: you may need to restart the kernel to use updated packages.\n"]},{"data":{},"execution_count":2,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Warning: PySpark kernel has been restarted to use updated packages.\n","\n"]}],"source":["%pip install wget"]},{"cell_type":"code","execution_count":3,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:25:13.0187836Z","execution_start_time":"2023-05-10T09:25:13.0184873Z","livy_statement_state":"available","parent_msg_id":"d4c4cf5b-21c4-4804-9db2-1f18a6be7733","queued_time":"2023-05-10T09:24:43.5454914Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":-1},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, -1, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{},"execution_count":3,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Collecting openai\n"," Downloading openai-0.27.6-py3-none-any.whl (71 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m71.9/71.9 kB\u001b[0m \u001b[31m1.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m\n","\u001b[?25hRequirement already satisfied: tqdm in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from openai) (4.65.0)\n","Requirement already satisfied: requests>=2.20 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from openai) (2.28.2)\n","Requirement already satisfied: aiohttp in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from openai) (3.8.4)\n","Requirement already satisfied: urllib3<1.27,>=1.21.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.20->openai) (1.26.14)\n","Requirement already satisfied: certifi>=2017.4.17 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.20->openai) (2022.12.7)\n","Requirement already satisfied: idna<4,>=2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.20->openai) (3.4)\n","Requirement already satisfied: charset-normalizer<4,>=2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.20->openai) (2.1.1)\n","Requirement already satisfied: attrs>=17.3.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (22.2.0)\n","Requirement already satisfied: frozenlist>=1.1.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (1.3.3)\n","Requirement already satisfied: multidict<7.0,>=4.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (6.0.4)\n","Requirement already satisfied: yarl<2.0,>=1.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (1.8.2)\n","Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (4.0.2)\n","Requirement already satisfied: aiosignal>=1.1.2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from aiohttp->openai) (1.3.1)\n","Installing collected packages: openai\n","Successfully installed openai-0.27.6\n","\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.1.2\u001b[0m\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49m/nfs4/pyenv-27214bb4-edfd-4fdd-b888-8a99075a1416/bin/python -m pip install --upgrade pip\u001b[0m\n","Note: you may need to restart the kernel to use updated packages.\n"]},{"data":{},"execution_count":3,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Warning: PySpark kernel has been restarted to use updated packages.\n","\n"]}],"source":["%pip install openai"]},{"cell_type":"code","execution_count":17,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:40:42.8774236Z","execution_start_time":"2023-05-10T09:40:42.8771662Z","livy_statement_state":"available","parent_msg_id":"7a7dfea4-d420-4b03-a2c6-82c65dfe177e","queued_time":"2023-05-10T09:40:30.9990512Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":-1},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, -1, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{},"execution_count":17,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: azure-kusto-data in /nfs4/pyenv-27214bb4-edfd-4fdd-b888-8a99075a1416/lib/python3.10/site-packages (4.1.4)\n","Requirement already satisfied: msal<2,>=1.9.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-kusto-data) (1.21.0)\n","Requirement already satisfied: python-dateutil>=2.8.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-kusto-data) (2.8.2)\n","Requirement already satisfied: azure-core<2,>=1.11.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-kusto-data) (1.26.4)\n","Requirement already satisfied: requests>=2.13.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-kusto-data) (2.28.2)\n","Requirement already satisfied: ijson~=3.1 in /nfs4/pyenv-27214bb4-edfd-4fdd-b888-8a99075a1416/lib/python3.10/site-packages (from azure-kusto-data) (3.2.0.post0)\n","Requirement already satisfied: azure-identity<2,>=1.5.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-kusto-data) (1.12.0)\n","Requirement already satisfied: six>=1.11.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-core<2,>=1.11.0->azure-kusto-data) (1.16.0)\n","Requirement already satisfied: typing-extensions>=4.3.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-core<2,>=1.11.0->azure-kusto-data) (4.5.0)\n","Requirement already satisfied: cryptography>=2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-identity<2,>=1.5.0->azure-kusto-data) (40.0.1)\n","Requirement already satisfied: msal-extensions<2.0.0,>=0.3.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from azure-identity<2,>=1.5.0->azure-kusto-data) (1.0.0)\n","Requirement already satisfied: PyJWT[crypto]<3,>=1.0.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from msal<2,>=1.9.0->azure-kusto-data) (2.6.0)\n","Requirement already satisfied: urllib3<1.27,>=1.21.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.13.0->azure-kusto-data) (1.26.14)\n","Requirement already satisfied: charset-normalizer<4,>=2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.13.0->azure-kusto-data) (2.1.1)\n","Requirement already satisfied: idna<4,>=2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.13.0->azure-kusto-data) (3.4)\n","Requirement already satisfied: certifi>=2017.4.17 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.13.0->azure-kusto-data) (2022.12.7)\n","Requirement already satisfied: cffi>=1.12 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from cryptography>=2.5->azure-identity<2,>=1.5.0->azure-kusto-data) (1.15.1)\n","Requirement already satisfied: portalocker<3,>=1.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from msal-extensions<2.0.0,>=0.3.0->azure-identity<2,>=1.5.0->azure-kusto-data) (2.7.0)\n","Requirement already satisfied: pycparser in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from cffi>=1.12->cryptography>=2.5->azure-identity<2,>=1.5.0->azure-kusto-data) (2.21)\n","\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.1.2\u001b[0m\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49m/nfs4/pyenv-27214bb4-edfd-4fdd-b888-8a99075a1416/bin/python -m pip install --upgrade pip\u001b[0m\n","Note: you may need to restart the kernel to use updated packages.\n"]},{"data":{},"execution_count":17,"metadata":{},"output_type":"execute_result"},{"name":"stdout","output_type":"stream","text":["Warning: PySpark kernel has been restarted to use updated packages.\n","\n"]}],"source":["%pip install azure-kusto-data"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["### Download precomputed Embeddings\n","\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["In this section we are going to load prepared embedding data, so you don't have to recompute the embeddings of Wikipedia articles with your own credits.\n"]},{"cell_type":"code","execution_count":5,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:25:28.6496025Z","execution_start_time":"2023-05-10T09:25:23.4822208Z","livy_statement_state":"available","parent_msg_id":"2d10f66b-3875-426b-abdf-b88b2d64d7ec","queued_time":"2023-05-10T09:24:44.1318823Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":17},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 17, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{"text/plain":["'vector_database_wikipedia_articles_embedded.zip'"]},"execution_count":7,"metadata":{},"output_type":"execute_result"}],"source":["import wget\n","\n","embeddings_url = \"https://cdn.openai.com/API/examples/data/vector_database_wikipedia_articles_embedded.zip\"\n","\n","# The file is ~700 MB so this will take some time\n","wget.download(embeddings_url)"]},{"cell_type":"code","execution_count":6,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:25:50.6601867Z","execution_start_time":"2023-05-10T09:25:28.9912827Z","livy_statement_state":"available","parent_msg_id":"093e0086-0bc4-4fb8-b656-3484f31b675e","queued_time":"2023-05-10T09:24:44.6002568Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":18},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 18, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["\n","import zipfile\n","\n","with zipfile.ZipFile(\"vector_database_wikipedia_articles_embedded.zip\",\"r\") as zip_ref:\n"," zip_ref.extractall(\"/lakehouse/default/Files/data\")"]},{"cell_type":"code","execution_count":7,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:31:38.5924721Z","execution_start_time":"2023-05-10T09:25:50.9770732Z","livy_statement_state":"available","parent_msg_id":"fab21836-4966-4068-8725-8fac982ca969","queued_time":"2023-05-10T09:24:44.8734372Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":19},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 19, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
\n","\n","\n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n","
idurltitletexttitle_vectorcontent_vectorvector_id
01https://simple.wikipedia.org/wiki/AprilAprilApril is the fourth month of the year in the J...[0.001009464613161981, -0.020700545981526375, ...[-0.011253940872848034, -0.013491976074874401,...0
12https://simple.wikipedia.org/wiki/AugustAugustAugust (Aug.) is the eighth month of the year ...[0.0009286514250561595, 0.000820168002974242, ...[0.0003609954728744924, 0.007262262050062418, ...1
26https://simple.wikipedia.org/wiki/ArtArtArt is a creative activity that expresses imag...[0.003393713850528002, 0.0061537534929811954, ...[-0.004959689453244209, 0.015772193670272827, ...2
38https://simple.wikipedia.org/wiki/AAA or a is the first letter of the English alph...[0.0153952119871974, -0.013759135268628597, 0....[0.024894846603274345, -0.022186409682035446, ...3
49https://simple.wikipedia.org/wiki/AirAirAir refers to the Earth's atmosphere. Air is a...[0.02224554680287838, -0.02044147066771984, -0...[0.021524671465158463, 0.018522677943110466, -...4
\n","
"],"text/plain":[" id url title \\\n","0 1 https://simple.wikipedia.org/wiki/April April \n","1 2 https://simple.wikipedia.org/wiki/August August \n","2 6 https://simple.wikipedia.org/wiki/Art Art \n","3 8 https://simple.wikipedia.org/wiki/A A \n","4 9 https://simple.wikipedia.org/wiki/Air Air \n","\n"," text \\\n","0 April is the fourth month of the year in the J... \n","1 August (Aug.) is the eighth month of the year ... \n","2 Art is a creative activity that expresses imag... \n","3 A or a is the first letter of the English alph... \n","4 Air refers to the Earth's atmosphere. Air is a... \n","\n"," title_vector \\\n","0 [0.001009464613161981, -0.020700545981526375, ... \n","1 [0.0009286514250561595, 0.000820168002974242, ... \n","2 [0.003393713850528002, 0.0061537534929811954, ... \n","3 [0.0153952119871974, -0.013759135268628597, 0.... \n","4 [0.02224554680287838, -0.02044147066771984, -0... \n","\n"," content_vector vector_id \n","0 [-0.011253940872848034, -0.013491976074874401,... 0 \n","1 [0.0003609954728744924, 0.007262262050062418, ... 1 \n","2 [-0.004959689453244209, 0.015772193670272827, ... 2 \n","3 [0.024894846603274345, -0.022186409682035446, ... 3 \n","4 [0.021524671465158463, 0.018522677943110466, -... 4 "]},"execution_count":11,"metadata":{},"output_type":"execute_result"}],"source":["import pandas as pd\n","\n","from ast import literal_eval\n","\n","article_df = pd.read_csv('/lakehouse/default/Files/data/vector_database_wikipedia_articles_embedded.csv')\n","# Read vectors from strings back into a list\n","article_df[\"title_vector\"] = article_df.title_vector.apply(literal_eval)\n","article_df[\"content_vector\"] = article_df.content_vector.apply(literal_eval)\n","article_df.head()\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["### Store vectors in a Kusto table\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["Create a table & load the vectors in Kusto based on the contents in the dataframe. The spark option CreakeIfNotExists will automatically create a table if it doesn't exist\n"]},{"cell_type":"code","execution_count":20,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:07.7982707Z","execution_start_time":"2023-05-10T09:41:07.4379451Z","livy_statement_state":"available","parent_msg_id":"0a5fca1c-3aae-4b95-86c8-e098d0369f95","queued_time":"2023-05-10T09:41:07.1656842Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":37},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 37, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["# replace with your AAD Tenant ID, Kusto Cluster URI, Kusto DB name and Kusto Table\n","AAD_TENANT_ID = \"\"\n","KUSTO_CLUSTER = \"\"\n","KUSTO_DATABASE = \"Vector\"\n","KUSTO_TABLE = \"Wiki\""]},{"cell_type":"code","execution_count":9,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:31:43.2629717Z","execution_start_time":"2023-05-10T09:31:39.5426716Z","livy_statement_state":"available","parent_msg_id":"ece408d2-5f62-4a31-acfb-530070444031","queued_time":"2023-05-10T09:24:45.2865763Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":21},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 21, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["\n","kustoOptions = {\"kustoCluster\": KUSTO_CLUSTER, \"kustoDatabase\" :KUSTO_DATABASE, \"kustoTable\" : KUSTO_TABLE }\n","\n","# Replace the auth method based on your desired authentication mechanism - https://github.com/Azure/azure-kusto-spark/blob/master/docs/Authentication.md\n","access_token=mssparkutils.credentials.getToken(kustoOptions[\"kustoCluster\"])"]},{"cell_type":"code","execution_count":10,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:31:48.9063385Z","execution_start_time":"2023-05-10T09:31:43.5930348Z","livy_statement_state":"available","parent_msg_id":"421b9d33-f3ce-4f20-a8d4-5d0958f240c9","queued_time":"2023-05-10T09:24:45.5199822Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":22},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 22, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"name":"stderr","output_type":"stream","text":["/opt/spark/python/lib/pyspark.zip/pyspark/sql/pandas/conversion.py:604: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.\n"]}],"source":["#Pandas data frame to spark dataframe\n","sparkDF=spark.createDataFrame(article_df)"]},{"cell_type":"code","execution_count":11,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:34:35.1205454Z","execution_start_time":"2023-05-10T09:31:49.2428848Z","livy_statement_state":"available","parent_msg_id":"7e182f67-e09f-4aa4-9fca-d67b13f01f19","queued_time":"2023-05-10T09:24:45.7895854Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[{"completionTime":"2023-05-10T09:32:55.544GMT","dataRead":0,"dataWritten":0,"description":"Job group for statement 23:\n# Write data to a Kusto table\nsparkDF.write. format(\"com.microsoft.kusto.spark.synapse.datasource\"). option(\"kustoCluster\",kustoOptions[\"kustoCluster\"]). option(\"kustoDatabase\",kustoOptions[\"kustoDatabase\"]). option(\"kustoTable\", kustoOptions[\"kustoTable\"]). option(\"accessToken\", access_token). option(\"tableCreateOptions\", \"CreateIfNotExist\").mode(\"Append\"). save()\n","jobGroup":"23","jobId":7,"killedTasksSummary":{},"name":"foreachPartition at KustoWriter.scala:116","numActiveStages":0,"numActiveTasks":0,"numCompletedIndices":8,"numCompletedStages":1,"numCompletedTasks":8,"numFailedStages":0,"numFailedTasks":0,"numKilledTasks":0,"numSkippedStages":0,"numSkippedTasks":0,"numTasks":8,"rowCount":0,"stageIds":[10],"status":"SUCCEEDED","submissionTime":"2023-05-10T09:32:00.547GMT"}],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":1,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":23},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 23, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["# Write data to a Kusto table\n","sparkDF.write. \\\n","format(\"com.microsoft.kusto.spark.synapse.datasource\"). \\\n","option(\"kustoCluster\",kustoOptions[\"kustoCluster\"]). \\\n","option(\"kustoDatabase\",kustoOptions[\"kustoDatabase\"]). \\\n","option(\"kustoTable\", kustoOptions[\"kustoTable\"]). \\\n","option(\"accessToken\", access_token). \\\n","option(\"tableCreateOptions\", \"CreateIfNotExist\").\\\n","mode(\"Append\"). \\\n","save()\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["### Prepare your OpenAI API key\n","# "]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["The OpenAI API key is used for vectorization of the documents and queries. You can follow the insturctions to create & retrieve your Azure OpenAI key and endpoint. https://learn.microsoft.com/en-us/azure/cognitive-services/openai/tutorials/embeddings\n","\n","\n","Please make sure to use the text-embedding-ada-002 (Version 2) model. Since the precomputed embeddings were created with text-embedding-ada-002 OpenAI model we also have to use it during search.\n"]},{"cell_type":"code","execution_count":26,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:51.4743874Z","execution_start_time":"2023-05-10T09:41:51.1273995Z","livy_statement_state":"available","parent_msg_id":"53239dc7-36b8-4cbc-a4db-ce263729cd4f","queued_time":"2023-05-10T09:41:50.8249073Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":43},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 43, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["import openai"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### If using Azure Open AI"]},{"cell_type":"code","execution_count":27,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:53.0029722Z","execution_start_time":"2023-05-10T09:41:52.6610261Z","livy_statement_state":"available","parent_msg_id":"9546736c-bebc-411d-a50a-6cf69eb5e70d","queued_time":"2023-05-10T09:41:52.3687239Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":44},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 44, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["openai.api_version = '2022-12-01'\n","openai.api_base = '' # Please add your endpoint here\n","openai.api_type = 'azure'\n","openai.api_key = '' # Please add your api key here\n","\n","def embed(query):\n"," # Creates embedding vector from user query\n"," embedded_query = openai.Embedding.create(\n"," input=query,\n"," deployment_id=\"embed\", #replace with your deployment id\n"," chunk_size=1\n"," )[\"data\"][0][\"embedding\"]\n"," return embedded_query"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### If using Open AI"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Only run this cell if you plan to use Open AI for embedding"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["openai.api_key = \"\"\n","\n","\n","def embed(query):\n"," # Creates embedding vector from user query\n"," embedded_query = openai.Embedding.create(\n"," input=query,\n"," model=\"text-embedding-ada-002\",\n"," )[\"data\"][0][\"embedding\"]\n"," return embedded_query"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Generate embedding for the search term"]},{"cell_type":"code","execution_count":28,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:56.2227563Z","execution_start_time":"2023-05-10T09:41:55.1887813Z","livy_statement_state":"available","parent_msg_id":"1001b7dc-2b09-421e-aca4-e7a2b17c7d0e","queued_time":"2023-05-10T09:41:54.8728344Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":45},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 45, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["\n","searchedEmbedding = embed(\"places where you worship\")\n","#print(searchedEmbedding)"]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["#### Semantic search in Kusto "]},{"attachments":{},"cell_type":"markdown","metadata":{"nteract":{"transient":{"deleting":false}}},"source":["We will search the Kusto table for the closest vectors.\n","\n","We will be using the series-cosine-similarity-fl UDF for similarity search. \n","\n","Please create the function in your database before proceeding -\n","https://learn.microsoft.com/en-us/azure/data-explorer/kusto/functions-library/series-cosine-similarity-fl?tabs=query-defined"]},{"cell_type":"code","execution_count":18,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:40:52.3506224Z","execution_start_time":"2023-05-10T09:40:51.397278Z","livy_statement_state":"available","parent_msg_id":"5c692f91-d611-4f22-a2f3-e008bb8d89d8","queued_time":"2023-05-10T09:40:46.211323Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":35},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 35, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["from azure.kusto.data import KustoClient, KustoConnectionStringBuilder\n","from azure.kusto.data.exceptions import KustoServiceError\n","from azure.kusto.data.helpers import dataframe_from_result_table\n","import pandas as pd"]},{"cell_type":"code","execution_count":21,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:14.0650747Z","execution_start_time":"2023-05-10T09:41:13.6897398Z","livy_statement_state":"available","parent_msg_id":"2e004b80-df5e-4873-8dc4-dc9b0fcdfd1b","queued_time":"2023-05-10T09:41:13.4128259Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":38},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 38, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["KCSB = KustoConnectionStringBuilder.with_aad_device_authentication(\n"," KUSTO_CLUSTER)\n","KCSB.authority_id = AAD_TENANT_ID"]},{"cell_type":"code","execution_count":22,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:41:17.1788945Z","execution_start_time":"2023-05-10T09:41:16.7709048Z","livy_statement_state":"available","parent_msg_id":"7b74117d-03a9-4963-9fbf-83dcf5eb33a8","queued_time":"2023-05-10T09:41:16.4790182Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":39},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 39, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["KUSTO_CLIENT = KustoClient(KCSB)"]},{"cell_type":"code","execution_count":31,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:45:56.5295656Z","execution_start_time":"2023-05-10T09:45:54.8312637Z","livy_statement_state":"available","parent_msg_id":"848897fc-69b2-4108-8cb7-844d8dd473d7","queued_time":"2023-05-10T09:45:54.458869Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":48},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 48, Finished, Available)"]},"metadata":{},"output_type":"display_data"}],"source":["KUSTO_QUERY = \"Wiki | extend similarity = series_cosine_similarity_fl(dynamic(\"+str(searchedEmbedding)+\"), content_vector,1,1) | top 10 by similarity desc \"\n","\n","RESPONSE = KUSTO_CLIENT.execute(KUSTO_DATABASE, KUSTO_QUERY)"]},{"cell_type":"code","execution_count":32,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:46:02.8573664Z","execution_start_time":"2023-05-10T09:46:02.496154Z","livy_statement_state":"available","parent_msg_id":"36d4dd76-ca76-4ce0-aa35-5cd8d7c26b6f","queued_time":"2023-05-10T09:46:02.2249009Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":49},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 49, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
\n","\n","\n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n","
idurltitletexttitle_vectorcontent_vectorvector_idsimilarity
0852https://simple.wikipedia.org/wiki/TempleTempleA temple is a building where people go to prac...[-0.021837441250681877, -0.007722342386841774,...[-0.0019541378132998943, 0.007151313126087189,...4130.834495
178094https://simple.wikipedia.org/wiki/Christian%20...Christian worshipIn Christianity, worship has been thought as b...[0.0017675267299637198, -0.008890199474990368,...[0.020530683919787407, 0.0024345638230443, -0....203200.832132
259154https://simple.wikipedia.org/wiki/Service%20of...Service of worshipA service of worship is a religious meeting wh...[-0.007969820871949196, 0.0004240311391185969,...[0.003784010885283351, -0.0030924836173653603,...155190.831633
351910https://simple.wikipedia.org/wiki/WorshipWorshipWorship is a word often used in religion. It ...[0.0036036288365721703, -0.01276545226573944, ...[0.007925753481686115, -0.0110504487529397, 0....140100.828185
429576https://simple.wikipedia.org/wiki/AltarAltarAn altar is a place, often a table, where a re...[0.007887467741966248, -0.02706138789653778, -...[0.023901859298348427, -0.031175222247838977, ...87080.824124
592507https://simple.wikipedia.org/wiki/ShrineShrineA shrine is a holy or sacred place with someth...[-0.011601685546338558, 0.006366696208715439, ...[0.016423320397734642, -0.0015560361789539456,...239450.823863
6815https://simple.wikipedia.org/wiki/SynagogueSynagogueA synagogue is a place where Jews meet to wors...[-0.017317570745944977, 0.0022673190105706453,...[-0.004515442531555891, 0.003739549545571208, ...3980.819942
768080https://simple.wikipedia.org/wiki/Shinto%20shrineShinto shrineA Shinto shrine is a sacred place or site wher...[0.0035740730818361044, 0.0028098472394049168,...[0.011014971882104874, 0.00042272370774298906,...181060.818475
857790https://simple.wikipedia.org/wiki/ChapelChapelA chapel is a place for Christian worship. The...[-0.01371884811669588, 0.0031672674231231213, ...[0.002526090247556567, 0.02482965588569641, 0....152600.817608
9142https://simple.wikipedia.org/wiki/Church%20%28...Church (building)A church is a building that was constructed to...[0.0021336888894438744, 0.0029748091474175453,...[0.016109377145767212, 0.022908871993422508, 0...740.812636
\n","
"],"text/plain":[" id url \\\n","0 852 https://simple.wikipedia.org/wiki/Temple \n","1 78094 https://simple.wikipedia.org/wiki/Christian%20... \n","2 59154 https://simple.wikipedia.org/wiki/Service%20of... \n","3 51910 https://simple.wikipedia.org/wiki/Worship \n","4 29576 https://simple.wikipedia.org/wiki/Altar \n","5 92507 https://simple.wikipedia.org/wiki/Shrine \n","6 815 https://simple.wikipedia.org/wiki/Synagogue \n","7 68080 https://simple.wikipedia.org/wiki/Shinto%20shrine \n","8 57790 https://simple.wikipedia.org/wiki/Chapel \n","9 142 https://simple.wikipedia.org/wiki/Church%20%28... \n","\n"," title text \\\n","0 Temple A temple is a building where people go to prac... \n","1 Christian worship In Christianity, worship has been thought as b... \n","2 Service of worship A service of worship is a religious meeting wh... \n","3 Worship Worship is a word often used in religion. It ... \n","4 Altar An altar is a place, often a table, where a re... \n","5 Shrine A shrine is a holy or sacred place with someth... \n","6 Synagogue A synagogue is a place where Jews meet to wors... \n","7 Shinto shrine A Shinto shrine is a sacred place or site wher... \n","8 Chapel A chapel is a place for Christian worship. The... \n","9 Church (building) A church is a building that was constructed to... \n","\n"," title_vector \\\n","0 [-0.021837441250681877, -0.007722342386841774,... \n","1 [0.0017675267299637198, -0.008890199474990368,... \n","2 [-0.007969820871949196, 0.0004240311391185969,... \n","3 [0.0036036288365721703, -0.01276545226573944, ... \n","4 [0.007887467741966248, -0.02706138789653778, -... \n","5 [-0.011601685546338558, 0.006366696208715439, ... \n","6 [-0.017317570745944977, 0.0022673190105706453,... \n","7 [0.0035740730818361044, 0.0028098472394049168,... \n","8 [-0.01371884811669588, 0.0031672674231231213, ... \n","9 [0.0021336888894438744, 0.0029748091474175453,... \n","\n"," content_vector vector_id similarity \n","0 [-0.0019541378132998943, 0.007151313126087189,... 413 0.834495 \n","1 [0.020530683919787407, 0.0024345638230443, -0.... 20320 0.832132 \n","2 [0.003784010885283351, -0.0030924836173653603,... 15519 0.831633 \n","3 [0.007925753481686115, -0.0110504487529397, 0.... 14010 0.828185 \n","4 [0.023901859298348427, -0.031175222247838977, ... 8708 0.824124 \n","5 [0.016423320397734642, -0.0015560361789539456,... 23945 0.823863 \n","6 [-0.004515442531555891, 0.003739549545571208, ... 398 0.819942 \n","7 [0.011014971882104874, 0.00042272370774298906,... 18106 0.818475 \n","8 [0.002526090247556567, 0.02482965588569641, 0.... 15260 0.817608 \n","9 [0.016109377145767212, 0.022908871993422508, 0... 74 0.812636 "]},"execution_count":33,"metadata":{},"output_type":"execute_result"}],"source":["df = dataframe_from_result_table(RESPONSE.primary_results[0])\n","df"]},{"cell_type":"code","execution_count":null,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[],"source":["searchedEmbedding = embed(\"unfortunate events in history\")\n"]},{"cell_type":"code","execution_count":35,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"nteract":{"transient":{"deleting":false}}},"outputs":[{"data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2023-05-10T09:48:43.6147167Z","execution_start_time":"2023-05-10T09:48:41.8371731Z","livy_statement_state":"available","parent_msg_id":"3dd276f3-a68e-44f7-8205-253d772aea18","queued_time":"2023-05-10T09:48:41.4581244Z","session_id":"7e5070d2-4560-4fb8-a3a8-6a594acd58ab","session_start_time":null,"spark_jobs":{"jobs":[],"limit":20,"numbers":{"FAILED":0,"RUNNING":0,"SUCCEEDED":0,"UNKNOWN":0},"rule":"ALL_DESC"},"spark_pool":null,"state":"finished","statement_id":52},"text/plain":["StatementMeta(, 7e5070d2-4560-4fb8-a3a8-6a594acd58ab, 52, Finished, Available)"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
\n","\n","\n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n","
idurltitletexttitle_vectorcontent_vectorvector_idsimilarity
0848https://simple.wikipedia.org/wiki/TragedyTragedyIn theatre, a tragedy as defined by Aristotle ...[-0.019502468407154083, -0.010160734876990318,...[-0.012951433658599854, -0.018836138769984245,...4100.851848
14469https://simple.wikipedia.org/wiki/The%20HolocaustThe HolocaustThe Holocaust, sometimes called The Shoah (), ...[-0.030233195051550865, -0.024401605129241943,...[-0.016398731619119644, -0.013267949223518372,...12030.847222
264216https://simple.wikipedia.org/wiki/List%20of%20...List of historical plaguesThis list contains famous or well documented o...[-0.010667890310287476, -0.0003575817099772393...[-0.010863155126571655, -0.0012196656316518784...168590.844411
34397https://simple.wikipedia.org/wiki/List%20of%20...List of disastersThis is a list of disasters, both natural and ...[-0.02713736332952976, -0.005278210621327162, ...[-0.023679986596107483, -0.006126823835074902,...11580.843063
423073https://simple.wikipedia.org/wiki/DisasterDisasterA disaster is something very not good that hap...[-0.018235962837934497, -0.020034968852996823,...[-0.02504003793001175, 0.007415903266519308, 0...72510.840334
54382https://simple.wikipedia.org/wiki/List%20of%20...List of terrorist incidentsThe following is a list by date of acts and fa...[-0.03989032283425331, -0.012808636762201786, ...[-0.045838188380002975, -0.01682935282588005, ...11490.836162
613528https://simple.wikipedia.org/wiki/A%20Series%2...A Series of Unfortunate EventsA Series of Unfortunate Events is a series of ...[0.0010618815431371331, -0.0267023965716362, -...[0.002801976166665554, -0.02904471382498741, -...43470.835172
742874https://simple.wikipedia.org/wiki/History%20of...History of the worldThe history of the world (also called human hi...[0.0026915925554931164, -0.022206028923392296,...[0.013645033352077007, -0.005165994167327881, ...116720.830243
84452https://simple.wikipedia.org/wiki/AccidentAccidentAn accident is when something goes wrong when ...[-0.004075294826179743, -0.0059883203357458115...[0.00926120299845934, 0.013705797493457794, 0....11900.826898
9324https://simple.wikipedia.org/wiki/HistoryHistoryHistory is the study of past events. People kn...[0.006603690329939127, -0.011856242083013058, ...[0.0048830462619662285, 0.0032003086525946856,...1700.824645
\n","
"],"text/plain":[" id url \\\n","0 848 https://simple.wikipedia.org/wiki/Tragedy \n","1 4469 https://simple.wikipedia.org/wiki/The%20Holocaust \n","2 64216 https://simple.wikipedia.org/wiki/List%20of%20... \n","3 4397 https://simple.wikipedia.org/wiki/List%20of%20... \n","4 23073 https://simple.wikipedia.org/wiki/Disaster \n","5 4382 https://simple.wikipedia.org/wiki/List%20of%20... \n","6 13528 https://simple.wikipedia.org/wiki/A%20Series%2... \n","7 42874 https://simple.wikipedia.org/wiki/History%20of... \n","8 4452 https://simple.wikipedia.org/wiki/Accident \n","9 324 https://simple.wikipedia.org/wiki/History \n","\n"," title \\\n","0 Tragedy \n","1 The Holocaust \n","2 List of historical plagues \n","3 List of disasters \n","4 Disaster \n","5 List of terrorist incidents \n","6 A Series of Unfortunate Events \n","7 History of the world \n","8 Accident \n","9 History \n","\n"," text \\\n","0 In theatre, a tragedy as defined by Aristotle ... \n","1 The Holocaust, sometimes called The Shoah (), ... \n","2 This list contains famous or well documented o... \n","3 This is a list of disasters, both natural and ... \n","4 A disaster is something very not good that hap... \n","5 The following is a list by date of acts and fa... \n","6 A Series of Unfortunate Events is a series of ... \n","7 The history of the world (also called human hi... \n","8 An accident is when something goes wrong when ... \n","9 History is the study of past events. People kn... \n","\n"," title_vector \\\n","0 [-0.019502468407154083, -0.010160734876990318,... \n","1 [-0.030233195051550865, -0.024401605129241943,... \n","2 [-0.010667890310287476, -0.0003575817099772393... \n","3 [-0.02713736332952976, -0.005278210621327162, ... \n","4 [-0.018235962837934497, -0.020034968852996823,... \n","5 [-0.03989032283425331, -0.012808636762201786, ... \n","6 [0.0010618815431371331, -0.0267023965716362, -... \n","7 [0.0026915925554931164, -0.022206028923392296,... \n","8 [-0.004075294826179743, -0.0059883203357458115... \n","9 [0.006603690329939127, -0.011856242083013058, ... \n","\n"," content_vector vector_id similarity \n","0 [-0.012951433658599854, -0.018836138769984245,... 410 0.851848 \n","1 [-0.016398731619119644, -0.013267949223518372,... 1203 0.847222 \n","2 [-0.010863155126571655, -0.0012196656316518784... 16859 0.844411 \n","3 [-0.023679986596107483, -0.006126823835074902,... 1158 0.843063 \n","4 [-0.02504003793001175, 0.007415903266519308, 0... 7251 0.840334 \n","5 [-0.045838188380002975, -0.01682935282588005, ... 1149 0.836162 \n","6 [0.002801976166665554, -0.02904471382498741, -... 4347 0.835172 \n","7 [0.013645033352077007, -0.005165994167327881, ... 11672 0.830243 \n","8 [0.00926120299845934, 0.013705797493457794, 0.... 1190 0.826898 \n","9 [0.0048830462619662285, 0.0032003086525946856,... 170 0.824645 "]},"execution_count":39,"metadata":{},"output_type":"execute_result"}],"source":["KUSTO_QUERY = \"Wiki | extend similarity = series_cosine_similarity_fl(dynamic(\"+str(searchedEmbedding)+\"), title_vector,1,1) | top 10 by similarity desc \"\n","RESPONSE = KUSTO_CLIENT.execute(KUSTO_DATABASE, KUSTO_QUERY)\n","\n","df = dataframe_from_result_table(RESPONSE.primary_results[0])\n","df"]}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"display_name":"Synapse PySpark","language":"Python","name":"synapse_pyspark"},"language_info":{"name":"python"},"notebook_environment":{},"save_output":true,"spark_compute":{"compute_id":"/trident/default","session_options":{"conf":{},"enableDebugMode":false}},"synapse_widget":{"state":{},"version":"0.1"},"trident":{"lakehouse":{"default_lakehouse":"7a5ec84c-e155-4d5f-a4e6-d49f4628d60b","default_lakehouse_name":"TempLH","default_lakehouse_workspace_id":"14a81bdb-d1c4-4808-9396-b12faab604c3","known_lakehouses":[{"id":"7a5ec84c-e155-4d5f-a4e6-d49f4628d60b"}]}},"widgets":{}},"nbformat":4,"nbformat_minor":0} diff --git a/examples/vector_databases/kusto/README.md b/examples/vector_databases/kusto/README.md new file mode 100644 index 00000000..1f27662b --- /dev/null +++ b/examples/vector_databases/kusto/README.md @@ -0,0 +1,34 @@ +# Kusto as a Vector database + + + +[Azure Data Explorer aka Kusto](https://azure.microsoft.com/en-us/products/data-explorer) is a cloud-based data analytics service that enables users to perform advanced analytics on large datasets in real-time. It is particularly well-suited for handling large volumes of data, making it an excellent choice for storing and searching vectors. + +Kusto supports a special data type called dynamic, which can store unstructured data such as arrays and properties bag. [Dynamic data type](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/scalar-data-types/dynamic) is perfect for storing vector values. You can further augment the vector value by storing metadata related to the original object as separate columns in your table. +Kusto also supports in-built function [series_cosine_similarity_fl](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/functions-library/series-cosine-similarity-fl) to perform vector similarity searches. + +[Get started](https://aka.ms/kustofree) with Kusto for free. + +![Kusto_Vector](./images/kusto_vector_db.png) + + + +## Getting started with Kusto and Open AI embedding + +### Demo Scenario + +![Wiki_embeddings](./images/wiki_embeddings.png) + +![semantic_search_flow](./images/semantic_search_user_flow.png) + +If you’d like to try this demo, please follow the instructions in the [Notebook](Getting_started_with_kusto_and_openai_embeddings.ipynb). + +It will allow you to - + +1. Use precomputed embeddings created by OpenAI API. + +2. Store the embeddings in Kusto. + +3. Convert raw text query to an embedding with OpenAI API. + +4. Use Kusto to perform cosine similarity search in the stored embeddings. \ No newline at end of file diff --git a/examples/vector_databases/kusto/images/kusto_vector_db.png b/examples/vector_databases/kusto/images/kusto_vector_db.png new file mode 100644 index 0000000000000000000000000000000000000000..8c71158e8807d91f7842d80dab2b8b1ea3378082 GIT binary patch literal 64243 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
=O;XARDx&iq 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 literal 0 HcmV?d00001 diff --git a/examples/vector_databases/kusto/images/semantic_search_user_flow.png b/examples/vector_databases/kusto/images/semantic_search_user_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..6db04ef24dffd8482c6515779ebf28c5a287b1db GIT binary patch literal 34171 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