Task #56
KG Entity μ€λͺ μλ μμ± β μ€ν 보κ³
μμ λͺ λ Ήμ΄
[π‘ NORMAL] ## KG Entity μ€λͺ
μλ μμ± (qwen3:4b via Ollama)
### λͺ©ν
KGμ Entity λ
Έλ μ€ summaryκ° μλ 26κ°μ λν΄ λ‘컬 Ollama(qwen3:4b)λ‘ μ€λͺ
μ μμ±νκ³ Neo4jμ μ
λ°μ΄νΈνλ€.
### λμ μν°ν° (US μ€λ³΅ 6κ° μ μΈ)
1. Bulgaria (Location)
2. Circuit Breaker (Concept)
3. Class struggle (Concept)
4. Corporate Governance (Concept)
5. Democratic governance (Policy)
6. Foreign Investment (Concept)
7. Hanbok (Asset)
8. Hanji (Asset)
9. Historical materialism (Concept)
10. Iran-Israel war (Campaign)
11. Kazakh language (Concept)
12. Minab (Location)
13. Minister of Planning and Budget (Person - μ§μ±
)
14. No Kings Protests (Campaign)
15. President Jer (Person)
16. Quantum Computing (Asset)
17. Russian language (Concept)
18. Saudi military base (Location)
19. Ultra-imperialism (Concept)
20. cyber domains (Concept)
21. household debt (Concept)
22. labor environment (Concept)
23. like-minded nations (Organization)
24. liquefied natural gas (LNG) (Asset)
25. military domains (Concept)
26. myocardial infarction (Concept)
### μ€ν λ°©λ²
1. **Python μ€ν¬λ¦½νΈ μμ±** (`/tmp/kg_enricher.py`):
```python
import httpx
import json
from neo4j import GraphDatabase
OLLAMA_API = "http://localhost:11434/api/chat"
MODEL = "qwen3:4b"
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = "neo4j" # κΈ°λ³Έκ°, μ€μ μ λ€λ₯Ό μ μμ
ENTITIES = [
("Bulgaria", "Location"),
("Circuit Breaker", "Concept"),
("Class struggle", "Concept"),
("Corporate Governance", "Concept"),
("Democratic governance", "Policy"),
("Foreign Investment", "Concept"),
("Hanbok", "Asset"),
("Hanji", "Asset"),
("Historical materialism", "Concept"),
("Iran-Israel war", "Campaign"),
("Kazakh language", "Concept"),
("Minab", "Location"),
("Minister of Planning and Budget", "Person"),
("No Kings Protests", "Campaign"),
("President Jer", "Person"),
("Quantum Computing", "Asset"),
("Russian language", "Concept"),
("Saudi military base", "Location"),
("Ultra-imperialism", "Concept"),
("cyber domains", "Concept"),
("household debt", "Concept"),
("labor environment", "Concept"),
("like-minded nations", "Organization"),
("liquefied natural gas (LNG)", "Asset"),
("military domains", "Concept"),
("myocardial infarction", "Concept"),
]
def query_ollama(name: str, entity_type: str) -> str:
prompt = f"""λ€μ μν°ν°μ λν΄ 2-3λ¬Έμ₯μΌλ‘ κ°κ²°νκ² μ€λͺ
ν΄μ€. μ§μ ν/μ μΉκ²½μ νμ λ§₯λ½μ μ°μ μν κ².
μν°ν°: {name}
νμ
: {entity_type}
μ€λͺ
(νκ΅μ΄, 2-3λ¬Έμ₯):"""
response = httpx.post(OLLAMA_API, json={
"model": MODEL,
"messages": [{"role": "user", "content": prompt}],
"stream": False,
"keep_alive": -1,
"options": {"temperature": 0.3, "top_k": 20}
}, timeout=60)
return response.json()["message"]["content"].strip()
def update_neo4j(name: str, summary: str, driver):
with driver.session() as session:
result = session.run(
"MATCH (n:Entity {name: $name}) SET n.summary = $summary RETURN count(n) as updated",
name=name, summary=summary
)
return result.single()["updated"]
def main():
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
results = []
for name, etype in ENTITIES:
print(f"μ²λ¦¬ μ€: {name}...")
try:
summary = query_ollama(name, etype)
updated = update_neo4j(name, summary, driver)
print(f" β
{name}: {summary[:50]}... (λ
Έλ {updated}κ° μ
λ°μ΄νΈ)")
results.append({"name": name, "type": etype, "summary": summary, "updated": updated})
except Exception as e:
print(f" β {name}: {e}")
results.append({"name": name, "type": etype, "error": str(e)})
driver.close()
with open("/tmp/kg_enricher_results.json", "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\nμλ£: {len([r for r in results if 'summary' in r])}/{len(ENTITIES)}κ° μ±κ³΅")
print("κ²°κ³Ό: /tmp/kg_enricher_results.json")
if __name__ == "__main__":
main()
```
2. **μ€ν**:
```bash
cd /
pip install neo4j httpx -q
python /tmp/kg_enricher.py
```
3. **Neo4j λΉλ°λ²νΈ νμΈ**:
- νκ²½λ³μ `NEO4J_PASSWORD` νμΈ: `echo $NEO4J_PASSWORD`
- Docker: `docker ps | grep neo4j`
- μ°κ²° μ€ν¨ μ λΉλ°λ²νΈ μ‘°μ
4. **κ²°κ³Ό νμΈ**:
- `/tmp/kg_enricher_results.json` νμΌ μΆλ ₯
- μ±κ³΅/μ€ν¨ κ°μ 보κ³
- μμ±λ summary μν 3κ° μΆλ ₯
5. **KG κ²μ¦**:
```cypher
MATCH (n:Entity) WHERE n.summary IS NOT NULL RETURN count(n) as enriched
```
### μλ£ ν 보κ³
- μ±κ³΅ν μν°ν° μ
- μ€ν¨ν νλͺ©κ³Ό μ΄μ
- μμ±λ summary μμ 3κ°
- Neo4j μ
λ°μ΄νΈ νμΈ κ²°κ³Ό