From b07846fa083a6293268416778f38731ada26c26b Mon Sep 17 00:00:00 2001 From: liyun11118 Date: Sat, 8 Feb 2025 20:53:48 +0800 Subject: [PATCH 1/2] feat: adapt graphrag_import_neo4j for CSV input format --- .../graphrag-neo4j-csv-visualization.PNG | Bin 0 -> 63055 bytes ...aphrag_import_neo4j_cypher_csvformat.ipynb | 1201 +++++++++++++++++ ...edbai_Full_Employees_GraphRAG_With_DOB.csv | 61 + 3 files changed, 1262 insertions(+) create mode 100755 examples_notebooks/community_contrib/neo4j/graphrag-neo4j-csv-visualization.PNG create mode 100755 examples_notebooks/community_contrib/neo4j/graphrag_import_neo4j_cypher_csvformat.ipynb create mode 100644 test_csvs/Lancedbai_Full_Employees_GraphRAG_With_DOB.csv diff --git a/examples_notebooks/community_contrib/neo4j/graphrag-neo4j-csv-visualization.PNG b/examples_notebooks/community_contrib/neo4j/graphrag-neo4j-csv-visualization.PNG new file mode 100755 index 0000000000000000000000000000000000000000..767e4b6eb3485fe0b66c66192dffd332bbe8fdfa GIT binary patch literal 63055 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 {0OEN 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%0D$z@gX$ck%yG+fZ&Pr5?tL}&^mJgO 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 T_u}P%enVf^NT*c$@}2(y3>3JS literal 0 HcmV?d00001 diff --git a/examples_notebooks/community_contrib/neo4j/graphrag_import_neo4j_cypher_csvformat.ipynb b/examples_notebooks/community_contrib/neo4j/graphrag_import_neo4j_cypher_csvformat.ipynb new file mode 100755 index 0000000000..aa4e11915d --- /dev/null +++ b/examples_notebooks/community_contrib/neo4j/graphrag_import_neo4j_cypher_csvformat.ipynb @@ -0,0 +1,1201 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "b4fea928", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Microsoft Corporation.\n", + "# Licensed under the MIT License." + ] + }, + { + "cell_type": "markdown", + "id": "0c4bc9ba", + "metadata": {}, + "source": [ + "# Neo4j Import of GraphRAG Result for CSV files\n", + "\n", + "This notebook imports the results of the GraphRAG indexing process into the Neo4j Graph database for further processing, analysis or visualization. The data is stored in CSV format. The path to the CSV files is specified in the `graphrag/test_csvs/Lancedbai_Full_Employees_GraphRAG_With_DOB.csv` variable.\n", + "\n", + "You can also build your own GenAI applications using Neo4j and a number of RAG strategies with LangChain, LlamaIndex, Haystack, and many other frameworks.\n", + "See: https://neo4j.com/labs/genai-ecosystem\n", + "\n", + "Here is what the end result looks like:\n", + "\n", + "![](./graphrag-neo4j-csv-visualization.PNG)" + ] + }, + { + "cell_type": "markdown", + "id": "aa3bdf9c", + "metadata": {}, + "source": [ + "# How to configure the settings.yml File\n", + "\n", + "```yaml\n", + "input:\n", + " type: file # Use 'blob' if processing data from blob storage\n", + " file_type: csv\n", + " base_dir: \"input\"\n", + " file_encoding: \"utf-8\"\n", + " file_pattern: \".*\\\\.csv$\"\n", + " source_column: \"source\" \n", + " text_column: \"text\"\n", + " timestamp_column: \"timestamp\"\n", + " timestamp_format: \"%Y-%m-%d\"\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "3924e246", + "metadata": {}, + "source": [ + "## How does it work?\n", + "\n", + "The notebook loads the parquet files from the `output` folder of your indexing process and loads them into Pandas dataframes.\n", + "It then uses a batching approach to send a slice of the data into Neo4j to create nodes and relationships and add relevant properties. The id-arrays on most entities are turned into relationships. \n", + "\n", + "All operations use MERGE, so they are idempotent, and you can run the script multiple times.\n", + "\n", + "If you need to clean out the database, you can run the following statement\n", + "\n", + "```cypher\n", + "MATCH (n)\n", + "CALL { WITH n DETACH DELETE n } IN TRANSACTIONS OF 25000 ROWS;\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adca1803", + "metadata": {}, + "outputs": [], + "source": [ + "GRAPHRAG_FOLDER = \"PATH_TO_OUTPUT/artifacts\"" + ] + }, + { + "cell_type": "markdown", + "id": "7fb27b941602401d91542211134fc71a", + "metadata": {}, + "source": [ + "### Depedendencies\n", + "\n", + "We only need Pandas and the neo4j Python driver with the rust extension for faster network transport." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b57beec0", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --quiet pandas neo4j-rust-ext" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3eeee95f-e4f2-4052-94fb-a5dc8ab542ae", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "import pandas as pd\n", + "from neo4j import GraphDatabase" + ] + }, + { + "cell_type": "markdown", + "id": "307dd2f4", + "metadata": {}, + "source": [ + "## Neo4j Installation\n", + "\n", + "You can create a free instance of Neo4j [online](https://console.neo4j.io). You get a credentials file that you can use for the connection credentials. You can also get an instance in any of the cloud marketplaces.\n", + "\n", + "If you want to install Neo4j locally either use [Neo4j Desktop](https://neo4j.com/download) or \n", + "the official Docker image: `docker run -e NEO4J_AUTH=neo4j/password -p 7687:7687 -p 7474:7474 neo4j` " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6c15443-4acb-4f91-88ea-4e08abaa4c29", + "metadata": {}, + "outputs": [], + "source": [ + "NEO4J_URI = \"neo4j://localhost\" # or neo4j+s://xxxx.databases.neo4j.io\n", + "NEO4J_USERNAME = \"neo4j\"\n", + "NEO4J_PASSWORD = \"\" # your password\n", + "NEO4J_DATABASE = \"neo4j\"\n", + "\n", + "# Create a Neo4j driver\n", + "driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USERNAME, NEO4J_PASSWORD))" + ] + }, + { + "cell_type": "markdown", + "id": "70f37ab6", + "metadata": {}, + "source": [ + "## Batched Import\n", + "\n", + "The batched import function takes a Cypher insert statement (needs to use the variable `value` for the row) and a dataframe to import.\n", + "It will send by default 1k rows at a time as query parameter to the database to be inserted." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d787bf7b-ac9b-4bfb-b140-a50a3fd205c5", + "metadata": {}, + "outputs": [], + "source": [ + "def batched_import(statement, df, batch_size=1000):\n", + " \"\"\"\n", + " Import a dataframe into Neo4j using a batched approach.\n", + "\n", + " Parameters: statement is the Cypher query to execute, df is the dataframe to import, and batch_size is the number of rows to import in each batch.\n", + " \"\"\"\n", + " total = len(df)\n", + " start_s = time.time()\n", + " for start in range(0, total, batch_size):\n", + " batch = df.iloc[start : min(start + batch_size, total)]\n", + " result = driver.execute_query(\n", + " \"UNWIND $rows AS value \" + statement,\n", + " rows=batch.to_dict(\"records\"),\n", + " database_=NEO4J_DATABASE,\n", + " )\n", + " print(result.summary.counters)\n", + " print(f\"{total} rows in {time.time() - start_s} s.\")\n", + " return total" + ] + }, + { + "cell_type": "markdown", + "id": "0fb45f42", + "metadata": {}, + "source": [ + "## Indexes and Constraints\n", + "\n", + "Indexes in Neo4j are only used to find the starting points for graph queries, e.g. quickly finding two nodes to connect.\n", + "Constraints exist to avoid duplicates, we create them mostly on id's of Entity types.\n", + "\n", + "We use some Types as markers with two underscores before and after to distinguish them from the actual entity types.\n", + "\n", + "The default relationship type here is `RELATED` but we could also infer a real relationship-type from the description or the types of the start and end-nodes.\n", + "\n", + "* `__Entity__`\n", + "* `__Document__`\n", + "* `__Chunk__`\n", + "* `__Community__`" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "ed7f212e-9148-424c-adc6-d81db9f8e5a5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "create constraint chunk_id if not exists for (c:__Chunk__) require c.id is unique\n", + "\n", + "create constraint document_id if not exists for (d:__Document__) require d.id is unique\n", + "\n", + "create constraint entity_id if not exists for (c:__Community__) require c.community is unique\n", + "\n", + "create constraint entity_id if not exists for (e:__Entity__) require e.id is unique\n", + "\n", + "create constraint entity_title if not exists for (e:__Entity__) require e.name is unique\n", + "\n", + "create constraint entity_title if not exists for (e:__Covariate__) require e.title is unique\n", + "\n", + "create constraint related_id if not exists for ()-[rel:RELATED]->() require rel.id is unique\n" + ] + } + ], + "source": [ + "# create constraints, idempotent operation\n", + "\n", + "statements = [\n", + " \"\\ncreate constraint chunk_id if not exists for (c:__Chunk__) require c.id is unique\",\n", + " \"\\ncreate constraint document_id if not exists for (d:__Document__) require d.id is unique\",\n", + " \"\\ncreate constraint entity_id if not exists for (c:__Community__) require c.community is unique\",\n", + " \"\\ncreate constraint entity_id if not exists for (e:__Entity__) require e.id is unique\",\n", + " \"\\ncreate constraint entity_title if not exists for (e:__Entity__) require e.name is unique\",\n", + " \"\\ncreate constraint entity_title if not exists for (e:__Covariate__) require e.title is unique\",\n", + " \"\\ncreate constraint related_id if not exists for ()-[rel:RELATED]->() require rel.id is unique\",\n", + " \"\\n\",\n", + "]\n", + "\n", + "for statement in statements:\n", + " if len((statement or \"\").strip()) > 0:\n", + " print(statement)\n", + " driver.execute_query(statement)" + ] + }, + { + "cell_type": "markdown", + "id": "beea073b", + "metadata": {}, + "source": [ + "## Import Process\n", + "\n", + "### Importing the Documents\n", + "\n", + "We're loading the parquet file for the documents and create nodes with their ids and add the title property.\n", + "We don't need to store text_unit_ids as we can create the relationships and the text content is also contained in the chunks." + ] + }, + { + "cell_type": "markdown", + "id": "0a8867dd", + "metadata": {}, + "source": [ + "For `create_final_documents.parquet`:\n", + "- Text format input uses `title` column\n", + "- CSV format input uses `text` column\n", + "\n", + "This means when importing documents:\n", + "- Text format parquet file: reads and processes the `title` column\n", + "- CSV format parquet file: reads and processes the `text` column" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "1ba023e7", + "metadata": {}, + "outputs": [ + { + "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", + "
idtext
011178d482ef61bf651611ed9f3a6c75a1bb166ad98edb9...Name: Ishita Mann, Designation: Automation Eng...
18479222f1f8933d7367006efb37a7af8753754c4c0dc29...Name: Riya Mallick, Designation: AI Engineer, ...
\n", + "
" + ], + "text/plain": [ + " id \\\n", + "0 11178d482ef61bf651611ed9f3a6c75a1bb166ad98edb9... \n", + "1 8479222f1f8933d7367006efb37a7af8753754c4c0dc29... \n", + "\n", + " text \n", + "0 Name: Ishita Mann, Designation: Automation Eng... \n", + "1 Name: Riya Mallick, Designation: AI Engineer, ... " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doc_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_documents.parquet\", columns=[\"id\", \"text\"]\n", + ")\n", + "doc_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96391c15", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'labels_added': 60, 'nodes_created': 60, 'properties_set': 120}\n", + "60 rows in 0.03634047508239746 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Import documents\n", + "statement = \"\"\"\n", + "MERGE (d:__Document__ {id:value.id})\n", + "SET d += value {.text}\n", + "\"\"\"\n", + "\n", + "batched_import(statement, doc_df)" + ] + }, + { + "cell_type": "markdown", + "id": "f97bbadb", + "metadata": {}, + "source": [ + "### Loading Text Units\n", + "\n", + "We load the text units, create a node per id and set the text and number of tokens.\n", + "Then we connect them to the documents that we created before." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0d825626", + "metadata": {}, + "outputs": [ + { + "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", + "
idtextn_tokensdocument_ids
0913f0820a9755495a456b3f9d25df7fa1da5628534d89e...Name: Ela Sarin, Designation: Software Enginee...36[03b6640b26cb709e45cf86bd502fa72037ef7095da26c...
17aa39f4da7a467af172480d070a9ffada3e3454e63cb90...Name: Inaaya Sengupta, Designation: AI Engine...39[0b3df84bc39312f6cc47dc4b653661999eabc1b24534d...
\n", + "
" + ], + "text/plain": [ + " id \\\n", + "0 913f0820a9755495a456b3f9d25df7fa1da5628534d89e... \n", + "1 7aa39f4da7a467af172480d070a9ffada3e3454e63cb90... \n", + "\n", + " text n_tokens \\\n", + "0 Name: Ela Sarin, Designation: Software Enginee... 36 \n", + "1 Name: Inaaya Sengupta, Designation: AI Engine... 39 \n", + "\n", + " document_ids \n", + "0 [03b6640b26cb709e45cf86bd502fa72037ef7095da26c... \n", + "1 [0b3df84bc39312f6cc47dc4b653661999eabc1b24534d... " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "text_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_text_units.parquet\",\n", + " columns=[\"id\", \"text\", \"n_tokens\", \"document_ids\"],\n", + ")\n", + "text_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ffd3d380-8710-46f5-b90a-04ed8482192c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'labels_added': 60, 'relationships_created': 60, 'nodes_created': 60, 'properties_set': 180}\n", + "60 rows in 0.04514002799987793 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "statement = \"\"\"\n", + "MERGE (c:__Chunk__ {id:value.id})\n", + "SET c += value {.text, .n_tokens}\n", + "WITH c, value\n", + "UNWIND value.document_ids AS document\n", + "MATCH (d:__Document__ {id:document})\n", + "MERGE (c)-[:PART_OF]->(d)\n", + "\"\"\"\n", + "\n", + "batched_import(statement, text_df)" + ] + }, + { + "cell_type": "markdown", + "id": "f01b2094", + "metadata": {}, + "source": [ + "### Loading Nodes\n", + "\n", + "For the nodes we store id, name, description, embedding (if available), human readable id." + ] + }, + { + "cell_type": "markdown", + "id": "f43c9e04", + "metadata": {}, + "source": [ + "For `create_final_entities.parquet`:\n", + "- Text format input uses `name` column \n", + "- CSV format input uses `title` column\n", + "\n", + "This means when importing entities:\n", + "- Text format parquet file: reads and processes the `name` column\n", + "- CSV format parquet file: reads and processes the `title` column" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2392f9e9", + "metadata": {}, + "outputs": [ + { + "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", + "
titletypedescriptionhuman_readable_ididtext_unit_ids
0ELA SARINPERSONEla Sarin is a Software Engineer based in Lond...0c1cdc5b3-4cf0-41b9-8133-fe0ae2325961[913f0820a9755495a456b3f9d25df7fa1da5628534d89...
1NAYANTARA IYERPERSONNayantara Iyer is a manager who oversees a tea...1f556bfa4-f43c-4110-83a9-c760009c37c5[913f0820a9755495a456b3f9d25df7fa1da5628534d89...
\n", + "
" + ], + "text/plain": [ + " title type description \\\n", + "0 ELA SARIN PERSON Ela Sarin is a Software Engineer based in Lond... \n", + "1 NAYANTARA IYER PERSON Nayantara Iyer is a manager who oversees a tea... \n", + "\n", + " human_readable_id id \\\n", + "0 0 c1cdc5b3-4cf0-41b9-8133-fe0ae2325961 \n", + "1 1 f556bfa4-f43c-4110-83a9-c760009c37c5 \n", + "\n", + " text_unit_ids \n", + "0 [913f0820a9755495a456b3f9d25df7fa1da5628534d89... \n", + "1 [913f0820a9755495a456b3f9d25df7fa1da5628534d89... " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "entity_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_entities.parquet\",\n", + " columns=[\n", + " \"title\", \n", + " \"type\",\n", + " \"description\",\n", + " \"human_readable_id\",\n", + " \"id\",\n", + " \"text_unit_ids\",\n", + " ],\n", + ")\n", + "entity_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d038114-0714-48ee-a48a-c421cd539661", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'labels_added': 119, 'relationships_created': 279, 'nodes_created': 119, 'properties_set': 476}\n", + "119 rows in 0.2919292449951172 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "119" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "entity_statement = \"\"\"\n", + "MERGE (e:__Entity__ {id:value.id})\n", + "SET e += value {.human_readable_id, .description, name:replace(value.title,'\"','')}\n", + "WITH e, value\n", + "CALL apoc.create.addLabels(e, case when coalesce(value.type,\"\") = \"\" then [] else [apoc.text.upperCamelCase(replace(value.type,'\"',''))] end) yield node\n", + "UNWIND value.text_unit_ids AS text_unit\n", + "MATCH (c:__Chunk__ {id:text_unit})\n", + "MERGE (c)-[:HAS_ENTITY]->(e)\n", + "\"\"\"\n", + "\n", + "batched_import(entity_statement, entity_df)" + ] + }, + { + "cell_type": "markdown", + "id": "018d4f87", + "metadata": {}, + "source": [ + "### Import Relationships\n", + "\n", + "For the relationships we find the source and target node by name, using the base `__Entity__` type.\n", + "After creating the `RELATED` relationships, we set the description as attribute." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b347a047", + "metadata": {}, + "outputs": [ + { + "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", + "
sourcetargetidweighthuman_readable_iddescriptiontext_unit_ids
0ELA SARINNAYANTARA IYERbab4f0e1-ea51-43ba-b2b4-a6ff6f4c290b9.00Ela Sarin is managed by Nayantara Iyer[913f0820a9755495a456b3f9d25df7fa1da5628534d89...
1ELA SARINLONDON50690419-52ea-4f8a-b9ba-d28f08ad31981.01Ela Sarin is located in London[913f0820a9755495a456b3f9d25df7fa1da5628534d89...
\n", + "
" + ], + "text/plain": [ + " source target id weight \\\n", + "0 ELA SARIN NAYANTARA IYER bab4f0e1-ea51-43ba-b2b4-a6ff6f4c290b 9.0 \n", + "1 ELA SARIN LONDON 50690419-52ea-4f8a-b9ba-d28f08ad3198 1.0 \n", + "\n", + " human_readable_id description \\\n", + "0 0 Ela Sarin is managed by Nayantara Iyer \n", + "1 1 Ela Sarin is located in London \n", + "\n", + " text_unit_ids \n", + "0 [913f0820a9755495a456b3f9d25df7fa1da5628534d89... \n", + "1 [913f0820a9755495a456b3f9d25df7fa1da5628534d89... " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rel_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_relationships.parquet\",\n", + " columns=[\n", + " \"source\",\n", + " \"target\",\n", + " \"id\",\n", + " \"weight\",\n", + " \"human_readable_id\",\n", + " \"description\",\n", + " \"text_unit_ids\",\n", + " ],\n", + ")\n", + "rel_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27900c01-89e1-4dec-9d5c-c07317c68baf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'relationships_created': 225, 'properties_set': 1125}\n", + "225 rows in 0.12598586082458496 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "225" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rel_statement = \"\"\"\n", + " MATCH (source:__Entity__ {name:replace(value.source,'\"','')})\n", + " MATCH (target:__Entity__ {name:replace(value.target,'\"','')})\n", + " // not necessary to merge on id as there is only one relationship per pair\n", + " MERGE (source)-[rel:RELATED {id: value.id}]->(target)\n", + " SET rel += value {.weight, .human_readable_id, .description, .text_unit_ids}\n", + " RETURN count(*) as createdRels\n", + "\"\"\"\n", + "\n", + "batched_import(rel_statement, rel_df)" + ] + }, + { + "cell_type": "markdown", + "id": "e6365dd7", + "metadata": {}, + "source": [ + "### Importing Communities\n", + "\n", + "For communities we import their id, title, level.\n", + "We connect the `__Community__` nodes to the start and end nodes of the relationships they refer to.\n", + "\n", + "Connecting them to the chunks they orignate from is optional, as the entites are already connected to the chunks." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c2fab66c", + "metadata": {}, + "outputs": [ + { + "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", + "
idleveltitletext_unit_idsrelationship_ids
0a0bd8993-7109-45f4-870d-16db412b616a0Community 0[2899252a7de3e801a03a25fc2275f849069be82c97619...[15755ab2-5931-4332-a4ef-25ab64bf8431, 2555d64...
16a8d6b53-3e0b-4345-ae27-4223e2a44ccc0Community 1[58985f8c9caa3ac1e72e1401e3f8fe3eaf45e30f14358...[2d10758b-096c-468a-956b-41e48f73aa0b, 62c20e7...
\n", + "
" + ], + "text/plain": [ + " id level title \\\n", + "0 a0bd8993-7109-45f4-870d-16db412b616a 0 Community 0 \n", + "1 6a8d6b53-3e0b-4345-ae27-4223e2a44ccc 0 Community 1 \n", + "\n", + " text_unit_ids \\\n", + "0 [2899252a7de3e801a03a25fc2275f849069be82c97619... \n", + "1 [58985f8c9caa3ac1e72e1401e3f8fe3eaf45e30f14358... \n", + "\n", + " relationship_ids \n", + "0 [15755ab2-5931-4332-a4ef-25ab64bf8431, 2555d64... \n", + "1 [2d10758b-096c-468a-956b-41e48f73aa0b, 62c20e7... " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "community_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_communities.parquet\",\n", + " columns=[\"id\", \"level\", \"title\", \"text_unit_ids\", \"relationship_ids\"],\n", + ")\n", + "\n", + "community_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "1351f7e3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'labels_added': 36, 'relationships_created': 221, 'nodes_created': 36, 'properties_set': 108}\n", + "36 rows in 0.24303984642028809 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "36" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "statement = \"\"\"\n", + "MERGE (c:__Community__ {community:value.id})\n", + "SET c += value {.level, .title}\n", + "/*\n", + "UNWIND value.text_unit_ids as text_unit_id\n", + "MATCH (t:__Chunk__ {id:text_unit_id})\n", + "MERGE (c)-[:HAS_CHUNK]->(t)\n", + "WITH distinct c, value\n", + "*/\n", + "WITH *\n", + "UNWIND value.relationship_ids as rel_id\n", + "MATCH (start:__Entity__)-[:RELATED {id:rel_id}]->(end:__Entity__)\n", + "MERGE (start)-[:IN_COMMUNITY]->(c)\n", + "MERGE (end)-[:IN_COMMUNITY]->(c)\n", + "RETURn count(distinct c) as createdCommunities\n", + "\"\"\"\n", + "\n", + "batched_import(statement, community_df)" + ] + }, + { + "cell_type": "markdown", + "id": "dd9adf50", + "metadata": {}, + "source": [ + "### Importing Community Reports\n", + "\n", + "Fo the community reports we create nodes for each communitiy set the id, community, level, title, summary, rank, and rank_explanation and connect them to the entities they are about.\n", + "For the findings we create the findings in context of the communities." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1be9e7a9-69ee-406b-bce5-95a9c41ecffe", + "metadata": {}, + "outputs": [ + { + "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", + "
idcommunityleveltitlesummaryfindingsrankrank_explanationfull_content
0e897ccf1e1014228b8f7bb067f8c6b2a181Software Engineers and Their Managers in Londo...The community consists of software engineers b...[{'explanation': 'Raghav Barad is a software e...3.5The impact severity rating is low to moderate,...# Software Engineers and Their Managers in Lon...
15fb58eabc6bf4a8a91ebbd1088231f05211Zain Sahota and Onkar Lata CommunityThe community revolves around Zain Sahota, a D...[{'explanation': 'Zain Sahota is a Data Scient...2.5The impact severity rating is low due to the l...# Zain Sahota and Onkar Lata Community\\n\\nThe ...
\n", + "
" + ], + "text/plain": [ + " id community level \\\n", + "0 e897ccf1e1014228b8f7bb067f8c6b2a 18 1 \n", + "1 5fb58eabc6bf4a8a91ebbd1088231f05 21 1 \n", + "\n", + " title \\\n", + "0 Software Engineers and Their Managers in Londo... \n", + "1 Zain Sahota and Onkar Lata Community \n", + "\n", + " summary \\\n", + "0 The community consists of software engineers b... \n", + "1 The community revolves around Zain Sahota, a D... \n", + "\n", + " findings rank \\\n", + "0 [{'explanation': 'Raghav Barad is a software e... 3.5 \n", + "1 [{'explanation': 'Zain Sahota is a Data Scient... 2.5 \n", + "\n", + " rank_explanation \\\n", + "0 The impact severity rating is low to moderate,... \n", + "1 The impact severity rating is low due to the l... \n", + "\n", + " full_content \n", + "0 # Software Engineers and Their Managers in Lon... \n", + "1 # Zain Sahota and Onkar Lata Community\\n\\nThe ... " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "community_report_df = pd.read_parquet(\n", + " f\"{GRAPHRAG_FOLDER}/create_final_community_reports.parquet\",\n", + " columns=[\n", + " \"id\",\n", + " \"community\",\n", + " \"level\",\n", + " \"title\",\n", + " \"summary\",\n", + " \"findings\",\n", + " \"rank\",\n", + " \"rank_explanation\",\n", + " \"full_content\",\n", + " ],\n", + ")\n", + "community_report_df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "5c6ed591-f98c-4403-9fde-8d4cb4c01cca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'_contains_updates': True, 'labels_added': 30, 'relationships_created': 26, 'nodes_created': 30, 'properties_set': 106}\n", + "4 rows in 0.12617111206054688 s.\n" + ] + }, + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Import communities\n", + "community_statement = \"\"\"\n", + "MERGE (c:__Community__ {community:value.community})\n", + "SET c += value {.level, .title, .rank, .rank_explanation, .full_content, .summary}\n", + "WITH c, value\n", + "UNWIND range(0, size(value.findings)-1) AS finding_idx\n", + "WITH c, value, finding_idx, value.findings[finding_idx] as finding\n", + "MERGE (c)-[:HAS_FINDING]->(f:Finding {id:finding_idx})\n", + "SET f += finding\n", + "\"\"\"\n", + "batched_import(community_statement, community_report_df)" + ] + }, + { + "cell_type": "markdown", + "id": "00340bae", + "metadata": {}, + "source": [ + "### Visualize your data\n", + "\n", + "You can now [Open] Neo4j on Aura, you need to log in with either SSO or your credentials.\n", + "\n", + "Or open https://workspace-preview.neo4j.io and connect to your local instance, remember the URI is `neo4j://localhost` and `neo4j` as username and `password` as password.\n", + "\n", + "In \"Explore\" you can explore by using visual graph patterns and then explore and expand further.\n", + "\n", + "In \"Query\", you can open the left sidebar and explore by clicking on the nodes and relationships.\n", + "You can also use the co-pilot to generate Cypher queries for your, here are some examples.\n", + "\n", + "#### Show a few `__Entity__` nodes and their relationships (Entity Graph)\n", + "\n", + "```cypher\n", + "MATCH path = (:__Entity__)-[:RELATED]->(:__Entity__)\n", + "RETURN path LIMIT 200\n", + "```\n", + "\n", + "#### Show the Chunks and the Document (Lexical Graph)\n", + "\n", + "```cypher\n", + "MATCH (d:__Document__) WITH d LIMIT 1\n", + "MATCH path = (d)<-[:PART_OF]-(c:__Chunk__)\n", + "RETURN path LIMIT 100\n", + "```\n", + "\n", + "#### Show a Community and it's Entities\n", + "\n", + "```cypher\n", + "MATCH (c:__Community__) WITH c LIMIT 1\n", + "MATCH path = (c)<-[:IN_COMMUNITY]-()-[:RELATED]-(:__Entity__)\n", + "RETURN path LIMIT 100\n", + "```\n", + "\n", + "#### Show everything\n", + "\n", + "```cypher\n", + "MATCH (d:__Document__) WITH d LIMIT 1\n", + "MATCH path = (d)<-[:PART_OF]-(:__Chunk__)-[:HAS_ENTIY]->()-[:RELATED]-()-[:IN_COMMUNITY]->()\n", + "RETURN path LIMIT 250\n", + "```\n", + "\n", + "We showed the visualization of this last query at the beginning." + ] + }, + { + "cell_type": "markdown", + "id": "a0aa8529", + "metadata": {}, + "source": [ + "If you have questions, feel free to reach out in the GraphRAG discord server: \n", + "https://discord.gg/graphrag" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.11.8 ('aiops')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + }, + "vscode": { + "interpreter": { + "hash": "ea4f075b2c5531f60d5e8540adc3d4423c92e30d4ea47d0118f65b1bc20f176f" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test_csvs/Lancedbai_Full_Employees_GraphRAG_With_DOB.csv b/test_csvs/Lancedbai_Full_Employees_GraphRAG_With_DOB.csv new file mode 100644 index 0000000000..2203182ab1 --- /dev/null +++ b/test_csvs/Lancedbai_Full_Employees_GraphRAG_With_DOB.csv @@ -0,0 +1,61 @@ +source,text,timestamp +Employee Dataset,"Name: Ishita Mann, Designation: Automation Engineer, Manager: Rasha Baral, Location: Pune, Date of Birth: 30-05-1995",2022-12-17 +Employee Dataset,"Name: Riya Mallick, Designation: AI Engineer, Manager: Rasha Baral, Location: Pune, Date of Birth: 15-07-1996",2023-06-27 +Employee Dataset,"Name: Divit Dara, Designation: Full Stack Developer, Manager: Rasha Baral, Location: Bangalore, Date of Birth: 03-09-2000",2024-03-10 +Employee Dataset,"Name: Alisha Kunda, Designation: AI Engineer, Manager: Shanaya Guha, Location: Bangalore, Date of Birth: 05-10-1985",2023-07-21 +Employee Dataset,"Name: Sahil Kamdar, Designation: Automation Engineer, Manager: Abram Rau, Location: Bangalore, Date of Birth: 17-02-2004",2024-05-28 +Employee Dataset,"Name: Faiyaz Deshmukh, Designation: Automation Engineer, Manager: Rasha Baral, Location: London, Date of Birth: 20-08-1998",2022-09-04 +Employee Dataset,"Name: Vihaan Sheth, Designation: Cloud Engineer, Manager: Khushi Magar, Location: London, Date of Birth: 17-06-2003",2023-12-01 +Employee Dataset,"Name: Shanaya Kaul, Designation: Data Engineer, Manager: Prerak Chand, Location: London, Date of Birth: 16-09-1996",2023-02-09 +Employee Dataset,"Name: Inaaya Sengupta, Designation: AI Engineer, Manager: Rasha Baral, Location: Pune, Date of Birth: 09-08-2001",2022-10-31 +Employee Dataset,"Name: Ela Sarin, Designation: Software Engineer, Manager: Nayantara Iyer, Location: London, Date of Birth: 02-03-1989",2022-12-28 +Employee Dataset,"Name: Shamik Brar, Designation: Cloud Engineer, Manager: Prerak Chand, Location: London, Date of Birth: 22-06-1996",2022-10-22 +Employee Dataset,"Name: Anvi Hayre, Designation: Full Stack Developer, Manager: Anaya Karpe, Location: Pune, Date of Birth: 25-07-2004",2023-10-01 +Employee Dataset,"Name: Fateh D’Alia, Designation: AI Engineer, Manager: Nayantara Iyer, Location: Pune, Date of Birth: 30-09-1987",2023-01-01 +Employee Dataset,"Name: Indranil Dani, Designation: Full Stack Developer, Manager: Prerak Chand, Location: Pune, Date of Birth: 04-01-1990",2023-02-08 +Employee Dataset,"Name: Kanav Dyal, Designation: Data Engineer, Manager: Onkar Wali, Location: Bangalore, Date of Birth: 09-01-2004",2022-11-07 +Employee Dataset,"Name: Rania Kota, Designation: Data Engineer, Manager: Himmat Solanki, Location: Pune, Date of Birth: 12-09-1991",2022-08-18 +Employee Dataset,"Name: Miraan Gandhi, Designation: Data Engineer, Manager: Prerak Chand, Location: Bangalore, Date of Birth: 08-03-2004",2023-10-28 +Employee Dataset,"Name: Pranay Raja, Designation: Data Engineer, Manager: Onkar Lata, Location: London, Date of Birth: 07-12-1995",2023-06-27 +Employee Dataset,"Name: Devansh Ghose, Designation: Data Scientist, Manager: Himmat Solanki, Location: Bangalore, Date of Birth: 31-05-1987",2024-06-02 +Employee Dataset,"Name: Dhanush Varma, Designation: Product Manager, Manager: Abram Rau, Location: Bangalore, Date of Birth: 06-04-1995",2022-11-12 +Employee Dataset,"Name: Advik Butala, Designation: AI Engineer, Manager: Onkar Wali, Location: London, Date of Birth: 22-05-1985",2024-05-15 +Employee Dataset,"Name: Raghav Barad, Designation: Software Engineer, Manager: Shanaya Guha, Location: Bangalore, Date of Birth: 08-10-1985",2022-12-23 +Employee Dataset,"Name: Zain Brahmbhatt, Designation: Automation Engineer, Manager: Nayantara Iyer, Location: Pune, Date of Birth: 16-03-1992",2024-04-13 +Employee Dataset,"Name: Darshit Yogi, Designation: Full Stack Developer, Manager: Rasha Baral, Location: Bangalore, Date of Birth: 26-01-1996",2023-04-29 +Employee Dataset,"Name: Mannat Sahota, Designation: Cloud Engineer, Manager: Shanaya Guha, Location: London, Date of Birth: 20-02-1992",2023-07-16 +Employee Dataset,"Name: Ivana Kala, Designation: Software Tester, Manager: Onkar Lata, Location: London, Date of Birth: 28-12-1998",2022-09-15 +Employee Dataset,"Name: Aaryahi Sarin, Designation: Automation Engineer, Manager: Onkar Lata, Location: Pune, Date of Birth: 21-08-1993",2024-03-21 +Employee Dataset,"Name: Neelofar Garg, Designation: AI Engineer, Manager: Nayantara Iyer, Location: Bangalore, Date of Birth: 17-04-1998",2023-07-11 +Employee Dataset,"Name: Jivika Badal, Designation: Cloud Engineer, Manager: Khushi Magar, Location: Bangalore, Date of Birth: 25-07-1993",2024-06-13 +Employee Dataset,"Name: Akarsh Bhatnagar, Designation: Software Engineer, Manager: Onkar Wali, Location: London, Date of Birth: 19-05-1999",2023-09-14 +Employee Dataset,"Name: Zain Sahota, Designation: Data Scientist, Manager: Onkar Lata, Location: Bangalore, Date of Birth: 11-12-1989",2024-05-25 +Employee Dataset,"Name: Jayan Kulkarni, Designation: Software Engineer, Manager: Onkar Lata, Location: London, Date of Birth: 06-11-1993",2024-07-09 +Employee Dataset,"Name: Sana Badami, Designation: Full Stack Developer, Manager: Nayantara Iyer, Location: Bangalore, Date of Birth: 25-05-1994",2023-01-10 +Employee Dataset,"Name: Jhanvi Dalal, Designation: Cloud Engineer, Manager: Khushi Magar, Location: London, Date of Birth: 14-12-1999",2024-03-07 +Employee Dataset,"Name: Emir Mani, Designation: AI Engineer, Manager: Prerak Chand, Location: Pune, Date of Birth: 12-10-1988",2023-04-13 +Employee Dataset,"Name: Ela Varkey, Designation: AI Engineer, Manager: Anaya Karpe, Location: London, Date of Birth: 27-01-1989",2022-09-07 +Employee Dataset,"Name: Dharmajan Virk, Designation: Data Scientist, Manager: Anaya Karpe, Location: Pune, Date of Birth: 07-04-1987",2023-09-23 +Employee Dataset,"Name: Prisha Bansal, Designation: Full Stack Developer, Manager: Prerak Chand, Location: London, Date of Birth: 06-01-1990",2024-06-03 +Employee Dataset,"Name: Ivana Wali, Designation: Software Tester, Manager: Nayantara Iyer, Location: Bangalore, Date of Birth: 05-01-1988",2023-12-11 +Employee Dataset,"Name: Aarush Bakshi, Designation: Data Scientist, Manager: Shanaya Guha, Location: London, Date of Birth: 27-10-1985",2024-05-03 +Employee Dataset,"Name: Farhan Goda, Designation: Software Tester, Manager: Abram Rau, Location: London, Date of Birth: 13-05-1990",2023-11-14 +Employee Dataset,"Name: Neelofar Sachdeva, Designation: Data Scientist, Manager: Nayantara Iyer, Location: Bangalore, Date of Birth: 09-02-1986",2023-04-14 +Employee Dataset,"Name: Kiara Bahri, Designation: Data Scientist, Manager: Khushi Magar, Location: Pune, Date of Birth: 04-07-1995",2023-02-08 +Employee Dataset,"Name: Hansh Sule, Designation: Automation Engineer, Manager: Rasha Baral, Location: London, Date of Birth: 12-07-1989",2024-03-07 +Employee Dataset,"Name: Anahita Sha, Designation: Product Manager, Manager: Onkar Wali, Location: Pune, Date of Birth: 05-06-1999",2023-09-24 +Employee Dataset,"Name: Shayak Andra, Designation: Automation Engineer, Manager: Khushi Magar, Location: London, Date of Birth: 29-01-1989",2024-03-15 +Employee Dataset,"Name: Yashvi Tak, Designation: AI Engineer, Manager: Khushi Magar, Location: Bangalore, Date of Birth: 01-01-1988",2023-03-13 +Employee Dataset,"Name: Pranay Raman, Designation: Software Engineer, Manager: Nayantara Iyer, Location: London, Date of Birth: 24-10-1999",2023-03-15 +Employee Dataset,"Name: Samar Thakur, Designation: Data Scientist, Manager: Onkar Wali, Location: Bangalore, Date of Birth: 30-09-2003",2023-06-07 +Employee Dataset,"Name: Rati Suresh, Designation: Data Engineer, Manager: Abram Rau, Location: Bangalore, Date of Birth: 07-06-1999",2022-11-14 +Employee Dataset,"Name: Arnav Ganesh, Designation: Software Engineer, Manager: Onkar Wali, Location: London, Date of Birth: 26-12-1989",2023-09-26 +Employee Dataset,"Name: Neysa Walla, Designation: Full Stack Developer, Manager: Onkar Wali, Location: Bangalore, Date of Birth: 26-12-1994",2024-06-25 +Employee Dataset,"Name: Anahi Deshpande, Designation: Software Engineer, Manager: Onkar Lata, Location: Pune, Date of Birth: 17-01-1987",2023-11-23 +Employee Dataset,"Name: Alia Saran, Designation: Full Stack Developer, Manager: Nayantara Iyer, Location: London, Date of Birth: 18-11-1993",2024-05-23 +Employee Dataset,"Name: Kanav Ganguly, Designation: Software Tester, Manager: Abram Rau, Location: Pune, Date of Birth: 01-03-1996",2023-01-06 +Employee Dataset,"Name: Samaira Sankar, Designation: Software Tester, Manager: Onkar Wali, Location: London, Date of Birth: 26-10-1987",2024-02-21 +Employee Dataset,"Name: Nayantara Sane, Designation: Product Manager, Manager: Khushi Magar, Location: London, Date of Birth: 21-07-1989",2024-08-09 +Employee Dataset,"Name: Purab Buch, Designation: AI Engineer, Manager: Shanaya Guha, Location: London, Date of Birth: 02-07-2004",2024-01-20 +Employee Dataset,"Name: Aarna Venkataraman, Designation: Cloud Engineer, Manager: Prerak Chand, Location: London, Date of Birth: 07-08-1993",2024-05-19 +Employee Dataset,"Name: Anika Jayaraman, Designation: Data Engineer, Manager: Nayantara Iyer, Location: Bangalore, Date of Birth: 11-11-1985",2023-03-21 From 995453dd4eee1a227d9f837c968720b4ca7970b4 Mon Sep 17 00:00:00 2001 From: liyun11118 Date: Sat, 8 Feb 2025 21:28:55 +0800 Subject: [PATCH 2/2] chore(version): Add minor change for CSV format support --- .semversioner/next-release/minor-20250208132110064499.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .semversioner/next-release/minor-20250208132110064499.json diff --git a/.semversioner/next-release/minor-20250208132110064499.json b/.semversioner/next-release/minor-20250208132110064499.json new file mode 100644 index 0000000000..8886486aec --- /dev/null +++ b/.semversioner/next-release/minor-20250208132110064499.json @@ -0,0 +1,4 @@ +{ + "type": "minor", + "description": "Add support for CSV format input in graphrag_import_neo4j" +}