Главная / Статьи

Полностью локальная пайплайн GraphRAG с использованием LangExtract, Neo4j, Qdrant и Ollama

Создайте GraphRAG на локальных моделях: извлеките сущности с помощью LangExtract, сохраните их в Neo4j, индексируйте в Qdrant, а затем расширяйте подграфы для получения ответов, основанных на структуре графа.

Издатель: REACTAPP.TOP39 мин чтения9040 слов

Источники: A Practical GraphRAG Architecture Using LangExtract, Neo4j, Qdrant, and Ollama

Эта версия — это система GraphRAG, которая полностью работает с локальными моделями. В её состав входят Ollama для обработки языка и моделей эмбеддингов, Neo4j для построения графа, Qdrant для векторного поиска и LangExtract для извлечения структуры из текста. Вместо загрузки фрагментов документов, как это делает обычный RAG, она преобразует необработанный текст в граф знаний, находит сущности, семантически близкие к вопросу, а затем следует за связями между ними.

Главным элементом этой конструкции является LangExtract, который находит сущности и связи в неструктурированном тексте и возвращает их в формате, пригодном для хранения в графе. Qdrant добавляет смысловую составляющую за счёт векторного сходства, а Neo4j обеспечивает контекст через прослеживание связей. Вместе они формируют систему поиска, учитывающую как тематику вопроса, так и способ связи между фактами.

Как работает архитектура

Чистый текст сначала попадает в слой LangExtract. В обычных работах документы сразу же делятся на фрагменты и встраиваются в структуру. Здесь же текст преобразуется в структурированные знания ещё до любых других действий. LangExtract, использующий модель, размещённую в Ollama, выделяет сущности и связи между ними. В приведённом примере речь идёт о данных о лекарствах: извлекаются названия препаратов, дозировки, частота приёма и медицинские состояния, причём связи между ними сохраняются благодаря общей группировке. Естественный язык превращается в структурированный отчёт о фактах, а не в набор сохранённых отрывков текста.

Далее извлеченные сущности и связи превращаются в элементы графа. Каждая концепция становится узлом с уникальным идентификатором, а такие связи, как дозировка, частота или состояние, превращаются в явные ребра между узлами. Теперь информация организована вокруг сущностей и их взаимосвязей, а не вокруг границ документов, что позволяет сохранять контекст, который при поиске на основе фрагментов обычно теряется.

Затем граф загружается в Neo4j — основной хранилище структурированных знаний. Сущности превращаются в узлы, а связи — в встроенные ребра. Поскольку Neo4j может эффективно перемещаться между связанными концепциями, система может позже следовать многократным путям и выявлять контекст, находящийся за пределами точки начала извлечения.

После построения графа для каждого узла создается эмбеддинг. Модель эмбеддингов считывает названия сущностей и концепции напрямую, а не целые документы или их фрагменты. В результате формируется семантический индекс графовых сущностей, что позволяет выполнять поиск на уровне концепций, а не отдельных фрагментов текста.

Эти векторы передаются в Qdrant вместе с соответствующими идентификаторами узлов Neo4j. Qdrant выполняет функции быстрого семантического слоя, в то время как Neo4j остается структурированным хранилищем. Поскольку каждый пакет данных в Qdrant содержит идентификатор узла Neo4j, совпадение векторов напрямую соответствует конкретной графовой сущности. Такое разделение позволяет каждой базе данных использовать свои сильные стороны: одна занимается поиском по сходству, а другая — просмотром связей и выполнением графовых вычислений.

В момент запроса пользователь задает вопрос на естественном языке. Тот же модель эмбеддингов преобразует его в вектор, который затем ищут в Qdrant для нахождения наиболее релевантных графовых сущностей. Вместо фрагментов документов поиск возвращает идентификаторы узлов. Эти узлы служат семантическими точками входа в граф, представляя концепции, наиболее близкие к тому, что хочет узнать пользователь.

Затем эти идентификаторы используются для формирования запроса к Neo4j. Вместо того чтобы останавливаться на найденных сущностях, система расширяет поиск через соседние узлы и связи, собирая релевантный подграф, включающий как совпадения, так и окружающий их контекст. Такое расширение позволяет собрать дополнительные факты, которые невозможно было бы обнаружить только с помощью векторного сходства, поэтому контекст обеспечивает одновременно семантическую релевантность и структуру.

Далее подграф преобразуется для использования в языковой модели. Узлы собираются в структурированный список, а связи превращаются в читаемые тройки, описывающие явные связи, такие как «доза Лизиноприла — 10 мг» или «Метформин при диабете». Этот шаг соединяет базы данных графов и языковые модели, преобразуя структуру графа в текст, который может интерпретировать модель.

Наконец, сформатированный контекст графа передается в ЯЗЫКОВУЮ МОДЕЛЬ. Модель получает сущности и связи, а не фрагменты информации, взятые из поиска, поэтому она может рассуждать на основе указанных фактов и не обязана выводить связи из разрозненных отрывков. Поскольку контекст формируется путем прослеживания связей в графе, он также более объясним и отслеживаем по сравнению с обычным векторным поиском.

В совокупности это гибридная система поиска. LangExtract отвечает за извлечение знаний, Neo4j управляет структурированными связями, Qdrant выполняет семантический поиск сущностей, а большая языковая модель анализирует контекст, основанный на графе. Сочетание методов сходства и прослеживания связей позволяет отвечать на вопросы, опираясь на связанное знание, а не на изолированные фрагменты текста. Благодаря этому подход особенно эффективен в таких областях, как здравоохранение, финансы, право, управление корпоративными знаниями и научные исследования, где связи между сущностями часто имеют большее значение, чем любой отдельный отрывок текста.

Метод за методом

__init__() является точкой входа для всей системы. Он считывает настройки из переменных окружения, включая учетные данные Neo4j, детали подключения к Qdrant и параметры Ollama. Он устанавливает соединения с Neo4j и Qdrant, которые используются остальной частью пайплайна, а также создает клиент Ollama, необходимый для извлечения данных, генерации векторных представлений и синтеза ответов. Имена моделей и размерности векторов хранятся в виде параметров, что позволяет настраивать работу системы.

def __init__(self,env_path: str = ".env",ollama_model_extract: str = "gemma3:latest",
            ollama_model_answer: str = "gemma3:latest",ollama_embedding_model: str = "embeddinggemma:latest",
            ollama_host: str | None = None,vector_dimension: int = 768,
    ):

        load_dotenv(env_path)

        self.qdrant_key = os.getenv("QDRANT_KEY")
        self.qdrant_url = os.getenv("QDRANT_URL")
        self.neo4j_uri = os.getenv("NEO4J_URI")
        self.neo4j_username = os.getenv("NEO4J_USERNAME")
        self.neo4j_password = os.getenv("NEO4J_PASSWORD")

        self.neo4j_driver = GraphDatabase.driver(
            self.neo4j_uri, auth=(self.neo4j_username, self.neo4j_password)
        )

        self.qdrant_client = QdrantClient(
            url=self.qdrant_url,
            api_key=self.qdrant_key,
        )

        # Ollama client for local embeddings (embeddinggemma:latest)
        self.ollama_client = ollama.Client(host=ollama_host) if ollama_host else ollama.Client()

        # langextract needs a plain URL string, not a client object
        self.ollama_url = ollama_host or os.environ.get("OLLAMA_HOST", "http://localhost:11434")

        # Model / config knobs
        self.ollama_model_extract = ollama_model_extract
        self.ollama_model_answer = ollama_model_answer
        self.ollama_embedding_model = ollama_embedding_model
        self.vector_dimension = vector_dimension

extract_graph_components() преобразует необработанный текст в структурированные знания. Он предоставляет инструкции по извлечению вместе с примерами, которые направляют LangExtract на поиск правильных сущностей и связей. Затем модель, размещенная на Ollama, обрабатывает входные данные и извлекает информацию о лекарствах, их дозировках, частоте применения и состояниях здоровья. Результатом остается набор извлеченных элементов, а не граф, поэтому метод передает их дальше для построения графа.

def extract_graph_components(self, raw_data: str):
        """Extract medication entities and relationships using langextract + Ollama."""

        prompt_description = textwrap.dedent("""
            Extract medications with their details, using attributes to group related information:
            1. Extract entities in the order they appear in the text
            2. Each entity must have a 'medication_group' attribute linking it to its medication
            3. All details about a medication should share the same medication_group value
            """).strip()

        examples = [
            lx.data.ExampleData(
                text=(
                    "Patient takes Aspirin 100mg daily for heart health and"
                    " Simvastatin 20mg at bedtime."
                ),
                extractions=[
                    lx.data.Extraction(
                        extraction_class="medication",
                        extraction_text="Aspirin",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="dosage",
                        extraction_text="100mg",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="frequency",
                        extraction_text="daily",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="condition",
                        extraction_text="heart health",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="medication",
                        extraction_text="Simvastatin",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="dosage",
                        extraction_text="20mg",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="frequency",
                        extraction_text="at bedtime",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                ],
            )
        ]

        result = lx.extract(
            text_or_documents=raw_data,
            prompt_description=prompt_description,
            examples=examples,
            model_id=self.ollama_model_extract,
            model_url=self.ollama_url,
            resolver_params={"format_handler": lx_ollama.OLLAMA_FORMAT_HANDLER},
            max_char_buffer=4000,
            show_progress=True,
        )

        return self._convert_extractions_to_graph(result.extractions)

_convert_extractions_to_graph() преобразует полученные данные в формат графа. Он объединяет связанные элементы вместе и выбирает основной объект каждой группы в качестве узла-анкора. Каждому узлу присваивается уникальный идентификатор, чтобы Neo4j и Qdrant сохраняли согласованность. Затем рёбра соединяют узлы-анкоры с их атрибутами, сохраняя первоначальный смысл. Результатом является набор узлов и рёбер, готовый к использованию в базе данных графов.

def _convert_extractions_to_graph(self, extractions: list):
        """Convert langextract's flat, grouped extractions into (nodes, relationships)."""

        groups: dict[str, list] = {}
        for ext in extractions:
            if not ext.attributes or "medication_group" not in ext.attributes:
                continue
            group_name = ext.attributes["medication_group"]
            groups.setdefault(group_name, []).append(ext)

        nodes: dict[str, str] = {}
        relationships: list[dict] = []

        for group_name, group_extractions in groups.items():
            anchor_ext = next(
                (e for e in group_extractions if e.extraction_class == "medication"),
                None,
            )

            # Fall back to the group name itself if no explicit "medication"
            # extraction was found in this group, so we still get an anchor.
            anchor_text = anchor_ext.extraction_text if anchor_ext else group_name

            if anchor_text not in nodes:
                nodes[anchor_text] = str(uuid.uuid4())

            for ext in group_extractions:
                if ext is anchor_ext:
                    continue

                target_text = ext.extraction_text
                if target_text not in nodes:
                    nodes[target_text] = str(uuid.uuid4())

                relationships.append(
                    {
                        "source": nodes[anchor_text],
                        "target": nodes[target_text],
                        "type": ext.extraction_class,
                    }
                )

        return nodes, relationships

ingest_to_neo4j() записывает граф в Neo4j, причем каждый объект хранится как узел, а каждая связь — как ребро. Такая структура обеспечивает эффективное просмотрение и дальнейшее исследование графа. Каждый узел сохраняет свой уникальный идентификатор, что позволяет связывать его с результатами векторного поиска. По окончании выполнения метода граф становится структурированным хранилищем знаний системы.

def ingest_to_neo4j(self, nodes: dict, relationships: list):
        """
        Ingest nodes and relationships into Neo4j.
        """
        with self.neo4j_driver.session() as session:
            # Create nodes in Neo4j
            for name, node_id in nodes.items():
                session.run(
                    "CREATE (n:Entity {id: $id, name: $name})",
                    id=node_id,
                    name=name,
                )

            # Create relationships in Neo4j, using the semantic type
            # (dosage/frequency/condition/etc.) as the actual relationship
            # label instead of a generic "RELATIONSHIP" type.
            for relationship in relationships:
                rel_type = self._sanitize_relationship_type(relationship["type"])
                session.run(
                    "MATCH (a:Entity {id: $source_id}), (b:Entity {id: $target_id}) "
                    f"CREATE (a)-[:{rel_type} {{type: $type}}]->(b)",
                    source_id=relationship["source"],
                    target_id=relationship["target"],
                    type=relationship["type"],
                )

        return nodes

_sanitize_relationship_type() существует потому, что названия связей формируются на основе вывода больших языковых моделей и могут содержать недопустимые символы или нестандартные форматы. Этот метод очищает и стандартизирует эти метки перед их отправкой в Neo4j, создавая безопасные идентификаторы верхнего регистра, соответствующие правилам Cypher. Он также защищает от некорректно сформированных названий и проблем с запросами, которые они могут вызвать. Хотя этот метод небольшой, он способствует поддержанию корректности графа.

@staticmethod
    def _sanitize_relationship_type(raw_type: str) -> str:
        """
        Cypher relationship types can't be passed as query parameters, so
        they have to be interpolated into the query string directly. Since
        raw_type comes from LLM-extracted text, sanitize it to a safe
        UPPER_SNAKE_CASE identifier before interpolation, to avoid Cypher
        injection or syntax errors from unexpected characters.
        """
        safe = "".join(ch if ch.isalnum() else "_" for ch in raw_type.strip())
        safe = safe.upper().strip("_") or "RELATIONSHIP"
        if safe[0].isdigit():
            safe = f"REL_{safe}"
        return safe

create_collection() гарантирует наличие коллекции в Qdrant перед сохранением любых векторов. Он проверяет, существует ли уже коллекция с указанным именем, и создаёт её в случае отсутствия, настраивая при этом размерность векторов и метрику сходства, используемые при поиске. Предварительная проверка позволяет избежать ненужного создания коллекций и готовит слой векторов к работе до начала загрузки данных.

def create_collection(self, collection_name: str, vector_dimension: int = None):
        vector_dimension = vector_dimension or self.vector_dimension

        try:
            # Try to fetch the collection status
            self.qdrant_client.get_collection(collection_name)
            print(f"Skipping creating collection; '{collection_name}' already exists.")
        except Exception as e:
            # If collection does not exist, an error will be thrown, so we create the collection
            if "Not found: Collection" in str(e) or "doesn't exist" in str(e) or "404" in str(e):
                print(f"Collection '{collection_name}' not found. Creating it now...")

                self.qdrant_client.create_collection(
                    collection_name=collection_name,
                    vectors_config=models.VectorParams(
                        size=vector_dimension, distance=models.Distance.COSINE
                    ),
                )

                print(f"Collection '{collection_name}' created successfully.")
            else:
                print(f"Error while checking collection: {e}")

ollama_embeddings() генерирует плотные векторы с использованием модели эмбеддингов Ollama. Каждый элемент графа и каждый запрос пользователя проходят через неё. Векторы численно отражают смысл, что позволяет эффективно сравнивать их, что обеспечивает поиск по сходству в Qdrant. По сути, этот метод служит мостом между естественным языком и поиском по векторам.

def ollama_embeddings(self, text: str) -> list[float]:
        response = self.ollama_client.embeddings(
            model=self.ollama_embedding_model,
            prompt=text,
        )
        return response["embedding"]

ingest_to_qdrant() создаёт эмбеддинг для каждого существа после того, как появляются узлы графа, и сохраняет его в Qdrant. Помимо вектора хранятся метаданные: идентификатор узла Neo4j и имя существа. Эта связь объединяет базу данных векторов с графовой базой данных, что позволяет позже преобразовывать результаты поиска обратно в графовые сущности. Этот метод формирует слой семантического поиска архитектуры.

def ingest_to_qdrant(self, collection_name: str, raw_data: str, node_id_mapping: dict):
        names = list(node_id_mapping.keys())
        embeddings = [self.ollama_embeddings(name) for name in names]

        self.qdrant_client.upsert(
            collection_name=collection_name,
            points=[
                {
                    "id": str(uuid.uuid4()),
                    "vector": embedding,
                    "payload": {"id": node_id_mapping[name], "name": name},
                }
                for name, embedding in zip(names, embeddings)
            ],
        )

retriever_search() выполняет семантическое поиск при вводе запроса. Запрос преобразуется в вектор и сравнивается с векторами в Qdrant. В результате возвращаются графовые сущности, похожие на запрос, а не фрагменты текста; эти сущности служат точками входа в граф знаний. Следовательно, поиск осуществляется на основе концепций, а не документов.

def retriever_search(self, collection_name: str, query: str, top_k: int = 5):
        retriever = QdrantNeo4jRetriever(
            driver=self.neo4j_driver,
            client=self.qdrant_client,
            collection_name=collection_name,
            id_property_external="id",
            id_property_neo4j="id",
        )

        results = retriever.search(
            query_vector=self.ollama_embeddings(query), top_k=top_k
        )

        return results

fetch_related_graph() запрашивает у Neo4j информацию о соседних элементах только что найденных сущностей. Он прослеживает структуру графа, собирая соседние узлы и связи, которые соединяют их с полученными сущностями. Такое расширение добавляет контекст, который мог быть упущен при векторном сравнении, и позволяет получить значимый подграф вместо изолированных сущностей. Этот шаг обеспечивает возможность GraphRAG анализировать связи между элементами.

def fetch_related_graph(self, entity_ids: list):
        query = """
        MATCH (e:Entity)-[r1]-(n1)-[r2]-(n2)
        WHERE e.id IN $entity_ids
        RETURN e, r1 as r, n1 as related, r2, n2
        UNION
        MATCH (e:Entity)-[r]-(related)
        WHERE e.id IN $entity_ids
        RETURN e, r, related, null as r2, null as n2
        """
        with self.neo4j_driver.session() as session:
            result = session.run(query, entity_ids=entity_ids)
            subgraph = []
            for record in result:
                subgraph.append(
                    {
                        "entity": record["e"],
                        "relationship": record["r"],
                        "related_node": record["related"],
                    }
                )
                if record["r2"] and record["n2"]:
                    subgraph.append(
                        {
                            "entity": record["related"],
                            "relationship": record["r2"],
                            "related_node": record["n2"],
                        }
                    )
        return subgraph

format_graph_context() готовит подграф для модели, поскольку сырой вывод графа не подходит для прямого использования в больших языковых моделях. Он преобразует структуру в чистый текст, состоящий из узлов и описаний связей, представленных в виде читаемых троек, которые указывают, как связаны сущности. Такой формат сохраняет структуру графа, при этом оставаясь понятным для языковой модели. Это последний этап подготовки контекста перед ответом.

def format_graph_context(self, subgraph: list):
        nodes = set()
        edges = []

        for entry in subgraph:
            entity = entry["entity"]
            related = entry["related_node"]
            relationship = entry["relationship"]

            nodes.add(entity["name"])
            nodes.add(related["name"])

            edges.append(f"{entity['name']} {relationship['type']} {related['name']}")

        return {"nodes": list(nodes), "edges": edges}

graphRAG_run() генерирует окончательный ответ. Он объединяет отформатированный контекст графа с вопросом пользователя в промпт. Модель получает информацию, связанную с графом, а не просто фрагменты документов, поэтому может анализировать взаимосвязи и связанные факты, причем её ответ основан на полученных знаниях из графа. Это слой рассуждений в конце процесса обработки.

def graphRAG_run(self, graph_context: dict, user_query: str):
        nodes_str = ", ".join(graph_context["nodes"])
        edges_str = "; ".join(graph_context["edges"])
        prompt = f"""
        You are an intelligent assistant with access to the following knowledge graph:

        Nodes: {nodes_str}

        Edges: {edges_str}

        Using this graph, Answer the following question:

        User Query: "{user_query}"
        """

        try:
            response = chat(
                model=self.ollama_model_answer,
                messages=[
                    {
                        "role": "system",
                        "content": "Provide the answer for the following question:",
                    },
                    {"role": "user", "content": prompt},
                ],
            )
            return response.message.content

        except Exception as e:
            return f"Error querying LLM: {str(e)}"

create_and_ingest() координирует весь процесс обработки данных: создание коллекции векторов, извлечение компонентов графа, их хранение в Neo4j, генерация эмбеддингов и индексирование сущностей в Qdrant. Его запуск преобразует необработанный текст в поисковую базу знаний GraphRAG. Обычно он выполняется один раз во время подготовки данных, после чего система может отвечать на запросы.

def create_and_ingest(self, raw_data: str, query: str, collection_name: str = "medicationGraphRAGstore"):
        print("Creating collection...")
        self.create_collection(collection_name, self.vector_dimension)
        print("Collection created/verified")

        print("Extracting graph components...")
        nodes, relationships = self.extract_graph_components(raw_data)
        print("Nodes:", nodes)
        print("Relationships:", relationships)

        print("Ingesting to Neo4j...")
        node_id_mapping = self.ingest_to_neo4j(nodes, relationships)
        print("Neo4j ingestion complete")

        print("Ingesting to Qdrant...")
        self.ingest_to_qdrant(collection_name, raw_data, node_id_mapping)
        print("Qdrant ingestion complete")

run_pipeline() координирует процесс получения информации и выполнение логических рассуждений от начала до конца. Он начинается с семантического поиска в Qdrant, определяет соответствующие графовые элементы и проходит по структуре Neo4j. Полученный подграф форматируется в виде контекста для модели рассуждений, а генерируемый ответ возвращается пользователю. Этот процесс отражает полный путь от вопроса до ответа.

def run_pipeline(self, raw_data: str, query: str, collection_name: str = "medicationGraphRAGstore"):

        # run only the first time, comment this for subsequent runs
        # self.create_and_ingest(raw_data, query, collection_name)

        print("Starting retriever search...")
        retriever_result = self.retriever_search(collection_name, query)
        print("Retriever results:", retriever_result)

        print("Extracting entity IDs...")
        entity_ids = [
            item.content.split("'id': '")[1].split("'")[0]
            for item in retriever_result.items
        ]
        print("Entity IDs:", entity_ids)

        print("Fetching related graph...")
        subgraph = self.fetch_related_graph(entity_ids)
        print("Subgraph:", subgraph)

        print("Formatting graph context...")
        graph_context = self.format_graph_context(subgraph)
        print("Graph context:", graph_context)

        print("Running GraphRAG...")
        answer = self.graphRAG_run(graph_context, query)
        print("Final Answer:", answer)

        return answer

close() отвечает за очистку. Он закрывает соединение драйвера Neo4j и освобождает связанные ресурсы, что предотвращает утечки соединений и позволяет осуществить плавное завершение работы. Этот метод прост в использовании, но его всегда следует вызывать по окончании обработки.

def close(self):
        self.neo4j_driver.close()

Код драйвера связывает классы между собой:

if __name__ == "__main__":
    print("Script started")

    graph_rag = MedicationGraphRAG(env_path="../.env")

    # Example-1
    # raw_data = textwrap.dedent("""
    #     The patient was prescribed Lisinopril and Metformin last month.
    #     He takes the Lisinopril 10mg daily for hypertension, but often misses
    #     his Metformin 500mg dose which should be taken twice daily for diabetes.
    #     """).strip()

    # Example-2
    raw_data = textwrap.dedent("""
    The patient is a 62-year-old man with a history of multiple chronic conditions
    being managed through an extensive medication regimen. He was prescribed
    Lisinopril, Metformin, Atorvastatin, Aspirin, Levothyroxine, and Sertraline
    over the course of the past year, with his treatment plan adjusted several
    times based on follow-up visits.

    He takes Lisinopril 10mg daily for hypertension, but often misses his
    Metformin 500mg dose which should be taken twice daily for diabetes. His
    cardiologist also started him on Atorvastatin 40mg at bedtime for high
    cholesterol after his last lipid panel showed elevated LDL levels. To reduce
    his risk of cardiovascular events, he was additionally prescribed Aspirin
    81mg daily for heart disease prevention, which he takes alongside his
    breakfast each morning.

    Following a routine thyroid screening, he was found to have an underactive
    thyroid and was started on Levothyroxine 75mcg every morning for
    hypothyroidism, to be taken on an empty stomach before any other medications.
    More recently, after reporting persistent low mood and difficulty sleeping
    during a wellness visit, his primary care physician added Sertraline 50mg
    daily for depression, with plans to reassess the dosage after eight weeks.

    Despite the number of prescriptions, the patient has had difficulty
    maintaining consistency with his Metformin and occasionally forgets his
    evening Atorvastatin dose, which his care team is now addressing through a
    simplified pill organizer and reminder system.
    """).strip()

    # Sample Questions
    #1. "What is the dosage and frequency for Lisinopril?"
    #2. "What is the dosage and frequency for Metformin?"
    #3. "Which medications does the patient take once daily versus twice daily?"
    #4. "What medication is prescribed for hypothyroidism, and at what dose?"
    #5. "List all medications related to cardiovascular conditions and their dosages."
    #6. "How often does the patient take Aspirin?"
    #7. "What condition is Levothyroxine prescribed for?"
    #8. "What time of day should Levothyroxine be taken, and why?"
    #9. "Which medications does the patient have trouble taking consistently?"
    #10. "What is the dosage and frequency for Sertraline?"

    query = "List all medications related to cardiovascular conditions and their dosages."

    answer = graph_rag.run_pipeline(raw_data, query, collection_name="medicationGraphRAGstore")

    graph_rag.close()

Полный скрипт

Все элементы вместе в одном файле:

import os
import uuid
import textwrap

import ollama
from dotenv import load_dotenv, find_dotenv
from ollama import chat
from neo4j import GraphDatabase
from qdrant_client import QdrantClient, models
from neo4j_graphrag.retrievers import QdrantNeo4jRetriever

import langextract as lx
from langextract.providers import ollama as lx_ollama

load_dotenv(find_dotenv())


class MedicationGraphRAG:

    def __init__(self,env_path: str = ".env",ollama_model_extract: str = "gemma3:latest",
            ollama_model_answer: str = "gemma3:latest",ollama_embedding_model: str = "embeddinggemma:latest",
            ollama_host: str | None = None,vector_dimension: int = 768,
    ):

        load_dotenv(env_path)

        self.qdrant_key = os.getenv("QDRANT_KEY")
        self.qdrant_url = os.getenv("QDRANT_URL")
        self.neo4j_uri = os.getenv("NEO4J_URI")
        self.neo4j_username = os.getenv("NEO4J_USERNAME")
        self.neo4j_password = os.getenv("NEO4J_PASSWORD")

        self.neo4j_driver = GraphDatabase.driver(
            self.neo4j_uri, auth=(self.neo4j_username, self.neo4j_password)
        )

        self.qdrant_client = QdrantClient(
            url=self.qdrant_url,
            api_key=self.qdrant_key,
        )

        # Ollama client for local embeddings (embeddinggemma:latest)
        self.ollama_client = ollama.Client(host=ollama_host) if ollama_host else ollama.Client()

        # langextract needs a plain URL string, not a client object
        self.ollama_url = ollama_host or os.environ.get("OLLAMA_HOST", "http://localhost:11434")

        # Model / config knobs
        self.ollama_model_extract = ollama_model_extract
        self.ollama_model_answer = ollama_model_answer
        self.ollama_embedding_model = ollama_embedding_model
        self.vector_dimension = vector_dimension

    def extract_graph_components(self, raw_data: str):
        """Extract medication entities and relationships using langextract + Ollama."""

        prompt_description = textwrap.dedent("""
            Extract medications with their details, using attributes to group related information:
            1. Extract entities in the order they appear in the text
            2. Each entity must have a 'medication_group' attribute linking it to its medication
            3. All details about a medication should share the same medication_group value
            """).strip()

        examples = [
            lx.data.ExampleData(
                text=(
                    "Patient takes Aspirin 100mg daily for heart health and"
                    " Simvastatin 20mg at bedtime."
                ),
                extractions=[
                    lx.data.Extraction(
                        extraction_class="medication",
                        extraction_text="Aspirin",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="dosage",
                        extraction_text="100mg",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="frequency",
                        extraction_text="daily",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="condition",
                        extraction_text="heart health",
                        attributes={"medication_group": "Aspirin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="medication",
                        extraction_text="Simvastatin",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="dosage",
                        extraction_text="20mg",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                    lx.data.Extraction(
                        extraction_class="frequency",
                        extraction_text="at bedtime",
                        attributes={"medication_group": "Simvastatin"},
                    ),
                ],
            )
        ]

        result = lx.extract(
            text_or_documents=raw_data,
            prompt_description=prompt_description,
            examples=examples,
            model_id=self.ollama_model_extract,
            model_url=self.ollama_url,
            resolver_params={"format_handler": lx_ollama.OLLAMA_FORMAT_HANDLER},
            max_char_buffer=4000,
            show_progress=True,
        )

        return self._convert_extractions_to_graph(result.extractions)

    def _convert_extractions_to_graph(self, extractions: list):
        """Convert langextract's flat, grouped extractions into (nodes, relationships)."""

        groups: dict[str, list] = {}
        for ext in extractions:
            if not ext.attributes or "medication_group" not in ext.attributes:
                continue
            group_name = ext.attributes["medication_group"]
            groups.setdefault(group_name, []).append(ext)

        nodes: dict[str, str] = {}
        relationships: list[dict] = []

        for group_name, group_extractions in groups.items():
            anchor_ext = next(
                (e for e in group_extractions if e.extraction_class == "medication"),
                None,
            )

            # Fall back to the group name itself if no explicit "medication"
            # extraction was found in this group, so we still get an anchor.
            anchor_text = anchor_ext.extraction_text if anchor_ext else group_name

            if anchor_text not in nodes:
                nodes[anchor_text] = str(uuid.uuid4())

            for ext in group_extractions:
                if ext is anchor_ext:
                    continue

                target_text = ext.extraction_text
                if target_text not in nodes:
                    nodes[target_text] = str(uuid.uuid4())

                relationships.append(
                    {
                        "source": nodes[anchor_text],
                        "target": nodes[target_text],
                        "type": ext.extraction_class,
                    }
                )

        return nodes, relationships

    def ingest_to_neo4j(self, nodes: dict, relationships: list):
        """
        Ingest nodes and relationships into Neo4j.
        """
        with self.neo4j_driver.session() as session:
            # Create nodes in Neo4j
            for name, node_id in nodes.items():
                session.run(
                    "CREATE (n:Entity {id: $id, name: $name})",
                    id=node_id,
                    name=name,
                )

            # Create relationships in Neo4j, using the semantic type
            # (dosage/frequency/condition/etc.) as the actual relationship
            # label instead of a generic "RELATIONSHIP" type.
            for relationship in relationships:
                rel_type = self._sanitize_relationship_type(relationship["type"])
                session.run(
                    "MATCH (a:Entity {id: $source_id}), (b:Entity {id: $target_id}) "
                    f"CREATE (a)-[:{rel_type} {{type: $type}}]->(b)",
                    source_id=relationship["source"],
                    target_id=relationship["target"],
                    type=relationship["type"],
                )

        return nodes

    @staticmethod
    def _sanitize_relationship_type(raw_type: str) -> str:
        """
        Cypher relationship types can't be passed as query parameters, so
        they have to be interpolated into the query string directly. Since
        raw_type comes from LLM-extracted text, sanitize it to a safe
        UPPER_SNAKE_CASE identifier before interpolation, to avoid Cypher
        injection or syntax errors from unexpected characters.
        """
        safe = "".join(ch if ch.isalnum() else "_" for ch in raw_type.strip())
        safe = safe.upper().strip("_") or "RELATIONSHIP"
        if safe[0].isdigit():
            safe = f"REL_{safe}"
        return safe

    def create_collection(self, collection_name: str, vector_dimension: int = None):
        vector_dimension = vector_dimension or self.vector_dimension

        try:
            # Try to fetch the collection status
            self.qdrant_client.get_collection(collection_name)
            print(f"Skipping creating collection; '{collection_name}' already exists.")
        except Exception as e:
            # If collection does not exist, an error will be thrown, so we create the collection
            if "Not found: Collection" in str(e) or "doesn't exist" in str(e) or "404" in str(e):
                print(f"Collection '{collection_name}' not found. Creating it now...")

                self.qdrant_client.create_collection(
                    collection_name=collection_name,
                    vectors_config=models.VectorParams(
                        size=vector_dimension, distance=models.Distance.COSINE
                    ),
                )

                print(f"Collection '{collection_name}' created successfully.")
            else:
                print(f"Error while checking collection: {e}")

    def ollama_embeddings(self, text: str) -> list[float]:
        response = self.ollama_client.embeddings(
            model=self.ollama_embedding_model,
            prompt=text,
        )
        return response["embedding"]

    def ingest_to_qdrant(self, collection_name: str, raw_data: str, node_id_mapping: dict):
        names = list(node_id_mapping.keys())
        embeddings = [self.ollama_embeddings(name) for name in names]

        self.qdrant_client.upsert(
            collection_name=collection_name,
            points=[
                {
                    "id": str(uuid.uuid4()),
                    "vector": embedding,
                    "payload": {"id": node_id_mapping[name], "name": name},
                }
                for name, embedding in zip(names, embeddings)
            ],
        )

    def retriever_search(self, collection_name: str, query: str, top_k: int = 5):
        retriever = QdrantNeo4jRetriever(
            driver=self.neo4j_driver,
            client=self.qdrant_client,
            collection_name=collection_name,
            id_property_external="id",
            id_property_neo4j="id",
        )

        results = retriever.search(
            query_vector=self.ollama_embeddings(query), top_k=top_k
        )

        return results

    def fetch_related_graph(self, entity_ids: list):
        query = """
        MATCH (e:Entity)-[r1]-(n1)-[r2]-(n2)
        WHERE e.id IN $entity_ids
        RETURN e, r1 as r, n1 as related, r2, n2
        UNION
        MATCH (e:Entity)-[r]-(related)
        WHERE e.id IN $entity_ids
        RETURN e, r, related, null as r2, null as n2
        """
        with self.neo4j_driver.session() as session:
            result = session.run(query, entity_ids=entity_ids)
            subgraph = []
            for record in result:
                subgraph.append(
                    {
                        "entity": record["e"],
                        "relationship": record["r"],
                        "related_node": record["related"],
                    }
                )
                if record["r2"] and record["n2"]:
                    subgraph.append(
                        {
                            "entity": record["related"],
                            "relationship": record["r2"],
                            "related_node": record["n2"],
                        }
                    )
        return subgraph

    def format_graph_context(self, subgraph: list):
        nodes = set()
        edges = []

        for entry in subgraph:
            entity = entry["entity"]
            related = entry["related_node"]
            relationship = entry["relationship"]

            nodes.add(entity["name"])
            nodes.add(related["name"])

            edges.append(f"{entity['name']} {relationship['type']} {related['name']}")

        return {"nodes": list(nodes), "edges": edges}

    def graphRAG_run(self, graph_context: dict, user_query: str):
        nodes_str = ", ".join(graph_context["nodes"])
        edges_str = "; ".join(graph_context["edges"])
        prompt = f"""
        You are an intelligent assistant with access to the following knowledge graph:

        Nodes: {nodes_str}

        Edges: {edges_str}

        Using this graph, Answer the following question:

        User Query: "{user_query}"
        """

        try:
            response = chat(
                model=self.ollama_model_answer,
                messages=[
                    {
                        "role": "system",
                        "content": "Provide the answer for the following question:",
                    },
                    {"role": "user", "content": prompt},
                ],
            )
            return response.message.content

        except Exception as e:
            return f"Error querying LLM: {str(e)}"

    def create_and_ingest(self, raw_data: str, query: str, collection_name: str = "medicationGraphRAGstore"):
        print("Creating collection...")
        self.create_collection(collection_name, self.vector_dimension)
        print("Collection created/verified")

        print("Extracting graph components...")
        nodes, relationships = self.extract_graph_components(raw_data)
        print("Nodes:", nodes)
        print("Relationships:", relationships)

        print("Ingesting to Neo4j...")
        node_id_mapping = self.ingest_to_neo4j(nodes, relationships)
        print("Neo4j ingestion complete")

        print("Ingesting to Qdrant...")
        self.ingest_to_qdrant(collection_name, raw_data, node_id_mapping)
        print("Qdrant ingestion complete")

    def run_pipeline(self, raw_data: str, query: str, collection_name: str = "medicationGraphRAGstore"):

        # run only the first time, comment this for subsequent runs
        # self.create_and_ingest(raw_data, query, collection_name)

        print("Starting retriever search...")
        retriever_result = self.retriever_search(collection_name, query)
        print("Retriever results:", retriever_result)

        print("Extracting entity IDs...")
        entity_ids = [
            item.content.split("'id': '")[1].split("'")[0]
            for item in retriever_result.items
        ]
        print("Entity IDs:", entity_ids)

        print("Fetching related graph...")
        subgraph = self.fetch_related_graph(entity_ids)
        print("Subgraph:", subgraph)

        print("Formatting graph context...")
        graph_context = self.format_graph_context(subgraph)
        print("Graph context:", graph_context)

        print("Running GraphRAG...")
        answer = self.graphRAG_run(graph_context, query)
        print("Final Answer:", answer)

        return answer

    def close(self):
        self.neo4j_driver.close()

if __name__ == "__main__":
    print("Script started")

    graph_rag = MedicationGraphRAG(env_path="../.env")

    # Example-1
    # raw_data = textwrap.dedent("""
    #     The patient was prescribed Lisinopril and Metformin last month.
    #     He takes the Lisinopril 10mg daily for hypertension, but often misses
    #     his Metformin 500mg dose which should be taken twice daily for diabetes.
    #     """).strip()

    # Example-2
    raw_data = textwrap.dedent("""
    The patient is a 62-year-old man with a history of multiple chronic conditions
    being managed through an extensive medication regimen. He was prescribed
    Lisinopril, Metformin, Atorvastatin, Aspirin, Levothyroxine, and Sertraline
    over the course of the past year, with his treatment plan adjusted several
    times based on follow-up visits.

    He takes Lisinopril 10mg daily for hypertension, but often misses his
    Metformin 500mg dose which should be taken twice daily for diabetes. His
    cardiologist also started him on Atorvastatin 40mg at bedtime for high
    cholesterol after his last lipid panel showed elevated LDL levels. To reduce
    his risk of cardiovascular events, he was additionally prescribed Aspirin
    81mg daily for heart disease prevention, which he takes alongside his
    breakfast each morning.

    Following a routine thyroid screening, he was found to have an underactive
    thyroid and was started on Levothyroxine 75mcg every morning for
    hypothyroidism, to be taken on an empty stomach before any other medications.
    More recently, after reporting persistent low mood and difficulty sleeping
    during a wellness visit, his primary care physician added Sertraline 50mg
    daily for depression, with plans to reassess the dosage after eight weeks.

    Despite the number of prescriptions, the patient has had difficulty
    maintaining consistency with his Metformin and occasionally forgets his
    evening Atorvastatin dose, which his care team is now addressing through a
    simplified pill organizer and reminder system.
    """).strip()

    # Sample Questions
    #1. "What is the dosage and frequency for Lisinopril?"
    #2. "What is the dosage and frequency for Metformin?"
    #3. "Which medications does the patient take once daily versus twice daily?"
    #4. "What medication is prescribed for hypothyroidism, and at what dose?"
    #5. "List all medications related to cardiovascular conditions and their dosages."
    #6. "How often does the patient take Aspirin?"
    #7. "What condition is Levothyroxine prescribed for?"
    #8. "What time of day should Levothyroxine be taken, and why?"
    #9. "Which medications does the patient have trouble taking consistently?"
    #10. "What is the dosage and frequency for Sertraline?"

    query = "List all medications related to cardiovascular conditions and their dosages."

    answer = graph_rag.run_pipeline(raw_data, query, collection_name="medicationGraphRAGstore")

    graph_rag.close()

Запуск

Три примера вопросов демонстрируют работу системы. Каждый из них выводит результаты поиска, а затем ответ, основанный на графе.

query = "List all medications related to cardiovascular conditions and their dosages."

Console:
Starting retriever search...
Retriever results: items=[RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}> score=0.5062605>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}> score=0.47961158>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}> score=0.45777896>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}> score=0.45199984>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}> score=0.4511963>", metadata=None)] metadata={'__retriever': 'QdrantNeo4jRetriever'}
Extracting entity IDs...
Entity IDs: ['1c9fb28e-c3e1-4515-afa0-01939beac419', '1db81626-c3de-4cab-b5dd-091327785182', '44573186-869f-4d5d-ba04-fe254ec4ed21', '04f27c55-38a3-46a9-a411-4faf07836a56', '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb']
Fetching related graph...
Subgraph: [{'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:5' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:4' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:5' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:3' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:5' labels=frozenset({'Entity'}) properties={'name': '81mg', 'id': '9d1d3859-cf6f-4a22-81b8-7d80e3cc8e89'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:5' labels=frozenset({'Entity'}) properties={'name': '81mg', 'id': '9d1d3859-cf6f-4a22-81b8-7d80e3cc8e89'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:17' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:4' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:2' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:3' labels=frozenset({'Entity'}) properties={'name': 'high cholesterol', 'id': 'dc85b413-3eca-4f26-a1dd-95de9d61e46c'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:3' labels=frozenset({'Entity'}) properties={'name': 'high cholesterol', 'id': 'dc85b413-3eca-4f26-a1dd-95de9d61e46c'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:1' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:2' labels=frozenset({'Entity'}) properties={'name': 'at bedtime', 'id': 'f9a049d4-bdb9-443d-a70f-3aa0ad290f5d'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:2' labels=frozenset({'Entity'}) properties={'name': 'at bedtime', 'id': 'f9a049d4-bdb9-443d-a70f-3aa0ad290f5d'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:0' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:0' labels=frozenset({'Entity'}) properties={'name': 'Atorvastatin', 'id': '1db81626-c3de-4cab-b5dd-091327785182'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:1' labels=frozenset({'Entity'}) properties={'name': '40mg', 'id': '960fd15d-ad36-4b90-aede-3473dd53f70c'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:1' labels=frozenset({'Entity'}) properties={'name': '40mg', 'id': '960fd15d-ad36-4b90-aede-3473dd53f70c'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:5' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:8' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:6' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}]
Formatting graph context...
Graph context: {'nodes': ['on an empty stomach before any other medications', 'hypertension', 'Atorvastatin', 'Lisinopril', 'Levothyroxine', 'at bedtime', 'high cholesterol', 'Aspirin', '75mcg', '81mg', 'daily', '10mg', 'heart disease prevention', 'every morning', 'Sertraline', 'hypothyroidism', '40mg'], 'edges': ['heart disease prevention condition Aspirin', 'Aspirin frequency daily', 'heart disease prevention condition Aspirin', 'Aspirin dosage 81mg', 'Lisinopril frequency daily', 'daily frequency Sertraline', 'Lisinopril frequency daily', 'daily frequency Aspirin', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine condition hypothyroidism', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine frequency every morning', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine dosage 75mcg', 'Atorvastatin condition high cholesterol', 'Atorvastatin frequency at bedtime', 'Atorvastatin dosage 40mg', 'heart disease prevention condition Aspirin', 'Levothyroxine route on an empty stomach before any other medications', 'Levothyroxine condition hypothyroidism', 'Levothyroxine frequency every morning', 'Levothyroxine dosage 75mcg', 'Lisinopril condition hypertension', 'Lisinopril frequency daily', 'Lisinopril dosage 10mg', 'on an empty stomach before any other medications route Levothyroxine']}
Running GraphRAG...
Final Answer: Here’s a list of medications related to cardiovascular conditions and their dosages based on the knowledge graph:

*   **Aspirin:** 81mg (frequency: daily) - for heart disease prevention.
*   **Atorvastatin:** 40mg (frequency: at bedtime) - for high cholesterol.
*   **Lisinopril:** 10mg (frequency: daily) - for hypertension.
query = "What medication is prescribed for hypothyroidism, and at what dose?"

Console:
Starting retriever search...
Retriever results: items=[RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}> score=0.6616618>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}> score=0.5983002>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}> score=0.4675771>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}> score=0.4620626>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}> score=0.4382253>", metadata=None)] metadata={'__retriever': 'QdrantNeo4jRetriever'}
Extracting entity IDs...
Entity IDs: ['95b91440-5ff1-41eb-a036-b57880094b05', '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb', 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847', '1c9fb28e-c3e1-4515-afa0-01939beac419', 'cddff401-0958-4093-b196-ad270b7aa797']
Fetching related graph...
Subgraph: [{'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:6' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:8' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:6' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:6' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:9' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}]
Formatting graph context...
Graph context: {'nodes': ['Lisinopril', '75mcg', 'twice daily', 'diabetes', 'on an empty stomach before any other medications', 'hypertension', 'daily', 'Metformin', '500mg', '10mg', 'hypothyroidism', 'Levothyroxine', 'every morning'], 'edges': ['10mg dosage Lisinopril', 'Lisinopril condition hypertension', '10mg dosage Lisinopril', 'Lisinopril frequency daily', 'hypothyroidism condition Levothyroxine', 'Levothyroxine route on an empty stomach before any other medications', 'hypothyroidism condition Levothyroxine', 'Levothyroxine frequency every morning', 'hypothyroidism condition Levothyroxine', 'Levothyroxine dosage 75mcg', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine condition hypothyroidism', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine frequency every morning', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine dosage 75mcg', 'Levothyroxine route on an empty stomach before any other medications', 'Levothyroxine condition hypothyroidism', 'Levothyroxine frequency every morning', 'Levothyroxine dosage 75mcg', '10mg dosage Lisinopril', 'Metformin condition diabetes', 'Metformin frequency twice daily', 'Metformin dosage 500mg', 'hypothyroidism condition Levothyroxine', 'on an empty stomach before any other medications route Levothyroxine']}
Running GraphRAG...
Final Answer: Levothyroxine 75mcg is prescribed for hypothyroidism, taken every morning.
query = "Which medications does the patient take once daily versus twice daily?"

Console:
Starting retriever search...
Retriever results: items=[RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}> score=0.6052238>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}> score=0.50138044>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}> score=0.424541>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}> score=0.42364278>", metadata=None), RetrieverResultItem(content="<Record node=<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}> score=0.4210245>", metadata=None)] metadata={'__retriever': 'QdrantNeo4jRetriever'}
Extracting entity IDs...
Entity IDs: ['73d5a502-05be-4bb7-916a-10b8ff5130fa', '1c9fb28e-c3e1-4515-afa0-01939beac419', '06da6faa-baa5-4657-a961-5091f58e3058', '9cbb512f-ca6b-47de-bb12-378ac35826bd', 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847']
Fetching related graph...
Subgraph: [{'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:17' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:18' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:22' labels=frozenset({'Entity'}) properties={'name': 'depression', 'id': '3aca7091-a4fa-4b12-ba5a-a8dbbbac5df4'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:22' labels=frozenset({'Entity'}) properties={'name': 'depression', 'id': '3aca7091-a4fa-4b12-ba5a-a8dbbbac5df4'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:17' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:16' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:21' labels=frozenset({'Entity'}) properties={'name': '50mg', 'id': '5fe00dee-bd0f-4476-b5a6-b19974033f78'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:21' labels=frozenset({'Entity'}) properties={'name': '50mg', 'id': '5fe00dee-bd0f-4476-b5a6-b19974033f78'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:4' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:5' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:6' labels=frozenset({'Entity'}) properties={'name': 'heart disease prevention', 'id': '44573186-869f-4d5d-ba04-fe254ec4ed21'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:4' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:3' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:5' labels=frozenset({'Entity'}) properties={'name': '81mg', 'id': '9d1d3859-cf6f-4a22-81b8-7d80e3cc8e89'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:5' labels=frozenset({'Entity'}) properties={'name': '81mg', 'id': '9d1d3859-cf6f-4a22-81b8-7d80e3cc8e89'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:8' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:11' labels=frozenset({'Entity'}) properties={'name': 'hypertension', 'id': '1bc0479e-5e00-4ede-8a9d-704e56f58814'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:6' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:9' labels=frozenset({'Entity'}) properties={'name': '10mg', 'id': 'cddff401-0958-4093-b196-ad270b7aa797'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:9' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:9' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:14' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:18' labels=frozenset({'Entity'}) properties={'name': 'hypothyroidism', 'id': '95b91440-5ff1-41eb-a036-b57880094b05'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:13' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:17' labels=frozenset({'Entity'}) properties={'name': 'every morning', 'id': '7fb1c7e5-e414-43ec-8606-474b08dc9173'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:12' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:16' labels=frozenset({'Entity'}) properties={'name': '75mcg', 'id': '75b6f7a1-2f53-419c-9365-5f026dcb1e25'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:17' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:20' labels=frozenset({'Entity'}) properties={'name': 'Sertraline', 'id': '42844c4c-ce96-4bd9-8d37-d8adad5a75fe'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:4' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:4' labels=frozenset({'Entity'}) properties={'name': 'Aspirin', 'id': '10939c85-6fc1-41b4-9b80-abe1662eda11'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:7' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:10' labels=frozenset({'Entity'}) properties={'name': 'daily', 'id': '06da6faa-baa5-4657-a961-5091f58e3058'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:8' labels=frozenset({'Entity'}) properties={'name': 'Lisinopril', 'id': '04f27c55-38a3-46a9-a411-4faf07836a56'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:9' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>) type='DOSAGE' properties={'type': 'dosage'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:13' labels=frozenset({'Entity'}) properties={'name': '500mg', 'id': '6c38fe32-0ca3-4bcc-a072-05e302aaa8e7'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:10' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:14' labels=frozenset({'Entity'}) properties={'name': 'twice daily', 'id': '73d5a502-05be-4bb7-916a-10b8ff5130fa'}>) type='FREQUENCY' properties={'type': 'frequency'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:11' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:15' labels=frozenset({'Entity'}) properties={'name': 'diabetes', 'id': '9cbb512f-ca6b-47de-bb12-378ac35826bd'}>) type='CONDITION' properties={'type': 'condition'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:12' labels=frozenset({'Entity'}) properties={'name': 'Metformin', 'id': 'd14d70ef-3780-4ebe-b803-1ab8bd8ec847'}>}, {'entity': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>, 'relationship': <Relationship element_id='5:a53f7783-1308-4f3d-9a27-45cede6b6376:15' nodes=(<Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>, <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:19' labels=frozenset({'Entity'}) properties={'name': 'on an empty stomach before any other medications', 'id': '1c9fb28e-c3e1-4515-afa0-01939beac419'}>) type='ROUTE' properties={'type': 'route'}>, 'related_node': <Node element_id='4:a53f7783-1308-4f3d-9a27-45cede6b6376:7' labels=frozenset({'Entity'}) properties={'name': 'Levothyroxine', 'id': '60654f2d-2ec8-4f4e-be02-cd57b7c5abfb'}>}]
Formatting graph context...
Graph context: {'nodes': ['twice daily', 'daily', '75mcg', '50mg', '81mg', 'Aspirin', 'on an empty stomach before any other medications', 'hypothyroidism', 'hypertension', 'depression', 'Lisinopril', 'Levothyroxine', 'heart disease prevention', 'every morning', 'Sertraline', 'diabetes', '500mg', '10mg', 'Metformin'], 'edges': ['daily frequency Sertraline', 'Sertraline condition depression', 'daily frequency Sertraline', 'Sertraline dosage 50mg', 'daily frequency Aspirin', 'Aspirin condition heart disease prevention', 'daily frequency Aspirin', 'Aspirin dosage 81mg', 'daily frequency Lisinopril', 'Lisinopril condition hypertension', 'daily frequency Lisinopril', 'Lisinopril dosage 10mg', 'twice daily frequency Metformin', 'Metformin condition diabetes', 'twice daily frequency Metformin', 'Metformin dosage 500mg', 'diabetes condition Metformin', 'Metformin frequency twice daily', 'diabetes condition Metformin', 'Metformin dosage 500mg', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine condition hypothyroidism', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine frequency every morning', 'on an empty stomach before any other medications route Levothyroxine', 'Levothyroxine dosage 75mcg', 'daily frequency Sertraline', 'daily frequency Aspirin', 'daily frequency Lisinopril', 'Metformin condition diabetes', 'Metformin frequency twice daily', 'Metformin dosage 500mg', 'twice daily frequency Metformin', 'diabetes condition Metformin', 'on an empty stomach before any other medications route Levothyroxine']}
Running GraphRAG...
Final Answer: Here’s the breakdown of medications taken once daily versus twice daily based on the knowledge graph:

**Once Daily:**

*   Aspirin: daily frequency
*   Sertraline: daily frequency
*   Levothyroxine: every morning frequency

**Twice Daily:**

*   Metformin: twice daily frequency

Что показывает процесс сборки

Результатом является полноценная платформа GraphRAG, в которой каждый компонент работает локально на Ollama, Neo4j, Qdrant и LangExtract. Неструктурированный текст преобразуется в структурированные знания благодаря извлечению сущностей и связей, причем эти знания хранятся в виде графа в Neo4j. Qdrant обеспечивает семантическое поисковое восстановление информации среди графовых сущностей и связывает векторный поиск с просмотром графа. Вместе они заменяют поиск на основе фрагментов текста поиском, учитывающим контекст и основанным на взаимосвязях знаний, что позволяет большим языковым моделям рассуждать на основе связей, а не изолированных фрагментов текста, в результате чего получаются более обоснованные и легко объяснимые ответы. Поскольку вся инфраструктура находится локально, разработчики сохраняют полный контроль над своими данными, моделями и инфраструктурой. По мере роста использования GraphRAG подобная архитектура представляет собой практический план для поиска, учитывающего взаимосвязи, созданного с использованием инструментов с открытым исходным кодом.