Skip to content

Commit e589c45

Browse files
committed
Add experimental Neo4J adapter
1 parent 3fcafd4 commit e589c45

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@
2121

2222
# customized config files
2323
/test/test_config.ini
24+
25+
# Neo4J Data
26+
compose_with_neo4j/data

compose_with_neo4j/compose.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
services:
2+
semantic_matching_service:
3+
build: ..
4+
container_name: semantic_matching_service
5+
restart: unless-stopped
6+
ports:
7+
- "8000:8000"
8+
working_dir: /app/semantic_matcher
9+
command: ["python", "service.py"]
10+
11+
neo4j:
12+
image: neo4j:latest
13+
container_name: neo4j
14+
volumes:
15+
- ./data/neo4j/logs:/logs
16+
- ./data/neo4j/config:/config
17+
- ./data/neo4j/data:/data
18+
- ./data/neo4j/plugins:/plugins
19+
environment:
20+
- NEO4J_AUTH=neo4j/your_password
21+
- NEO4J_dbms_usage__report_enabled=false
22+
ports:
23+
- "7474:7474"
24+
- "7687:7687"
25+
restart: always

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies = [
1717
"uvicorn>=0.21.1",
1818
"requests>=2.31.0",
1919
"networkx>=3.4.2",
20+
2021
]
2122

2223
[project.optional-dependencies]
@@ -27,6 +28,9 @@ dev = [
2728
"types-networkx", # Type hints for networkx
2829
"types-requests", # Type hints for requests
2930
]
31+
neo4j = [
32+
"neo4j>=5.28.1",
33+
]
3034

3135
[tool.setuptools]
3236
packages = { find = { include = ["semantic_matcher"], exclude = ["test*"] } }

semantic_matcher/algorithm.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import networkx as nx
66
from pydantic import BaseModel
7+
from neo4j import GraphDatabase
78

89

910
class SemanticMatchGraph(nx.DiGraph):
@@ -53,6 +54,34 @@ def from_file(cls, filename: str) -> "SemanticMatchGraph":
5354
)
5455
return graph
5556

57+
def to_neo4j(self, url: str, user: str, password: str):
58+
driver = GraphDatabase.driver(url, auth=(user, password))
59+
with driver.session() as session:
60+
# Optional: clear previous graph
61+
session.run("MATCH (n) DETACH DELETE n")
62+
63+
for u, v, data in self.edges(data=True):
64+
session.run("""
65+
MERGE (a:Semantic {id: $u})
66+
MERGE (b:Semantic {id: $v})
67+
MERGE (a)-[:MATCH {score: $score}]->(b)
68+
""", u=u, v=v, score=data["weight"])
69+
driver.close()
70+
71+
@classmethod
72+
def from_neo4j(cls, url: str, user: str, password: str) -> "SemanticMatchGraph":
73+
graph = cls()
74+
driver = GraphDatabase.driver(url, auth=(user, password))
75+
with driver.session() as session:
76+
result = session.run("""
77+
MATCH (a:Semantic)-[r:MATCH]->(b:Semantic)
78+
RETURN a.id AS u, b.id AS v, r.score AS score
79+
""")
80+
for record in result:
81+
graph.add_semantic_match(record["u"], record["v"], record["score"])
82+
driver.close()
83+
return graph
84+
5685

5786
class SemanticMatch(BaseModel):
5887
base_semantic_id: str
@@ -145,3 +174,17 @@ def find_semantic_matches(
145174
heapq.heappush(pq, (-new_score, neighbor, path + [node])) # Push updated path
146175

147176
return results
177+
178+
179+
if __name__ == '__main__':
180+
graph_complex = SemanticMatchGraph()
181+
graph_complex.add_edge("A", "B", weight=0.9)
182+
graph_complex.add_edge("A", "C", weight=0.8)
183+
graph_complex.add_edge("B", "D", weight=0.7)
184+
graph_complex.add_edge("C", "D", weight=0.6)
185+
graph_complex.add_edge("D", "E", weight=0.5)
186+
graph_complex.to_neo4j(
187+
url="bolt://localhost:7687",
188+
user="neo4j",
189+
password="your_password"
190+
)

0 commit comments

Comments
 (0)