mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 16:36:21 +02:00
770 lines
24 KiB
Markdown
770 lines
24 KiB
Markdown
|
|
---
|
|||
|
|
layout: default
|
|||
|
|
title: "Ontoloji Bilgi Çıkarma - 2. Aşama Yeniden Düzenleme"
|
|||
|
|
parent: "Turkish (Beta)"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Ontoloji Bilgi Çıkarma - 2. Aşama Yeniden Düzenleme
|
|||
|
|
|
|||
|
|
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
|||
|
|
|
|||
|
|
**Durum**: Taslak
|
|||
|
|
**Yazar**: Analiz Oturumu 2025-12-03
|
|||
|
|
**İlgili**: `ontology.md`, `ontorag.md`
|
|||
|
|
|
|||
|
|
## Genel Bakış
|
|||
|
|
|
|||
|
|
Bu belge, mevcut ontoloji tabanlı bilgi çıkarma sistemindeki tutarsızlıkları belirlemektedir ve LLM performansını iyileştirmek ve bilgi kaybını azaltmak için bir yeniden düzenleme önermektedir.
|
|||
|
|
|
|||
|
|
## Mevcut Uygulama
|
|||
|
|
|
|||
|
|
### Şu Anda Nasıl Çalışıyor
|
|||
|
|
|
|||
|
|
1. **Ontoloji Yükleme** (`ontology_loader.py`)
|
|||
|
|
`"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` gibi anahtarlara sahip ontoloji JSON'unu yükler.
|
|||
|
|
Sınıf kimlikleri, anahtar içinde namespace önekini içerir.
|
|||
|
|
`food.ontology`'dan bir örnek:
|
|||
|
|
```json
|
|||
|
|
"classes": {
|
|||
|
|
"fo/Recipe": {
|
|||
|
|
"uri": "http://purl.org/ontology/fo/Recipe",
|
|||
|
|
"rdfs:comment": "A Recipe is a combination..."
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **İstem Oluşturma** (`extract.py:299-307`, `ontology-prompt.md`)
|
|||
|
|
Şablon, `classes`, `object_properties`, `datatype_properties` sözlüklerini alır.
|
|||
|
|
Şablon döngüye girer: `{% for class_id, class_def in classes.items() %}`
|
|||
|
|
LLM (Büyük Dil Modeli) şunları görür: `**fo/Recipe**: A Recipe is a combination...`
|
|||
|
|
Örnek çıktı formatı şöyledir:
|
|||
|
|
```json
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"}
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **Yanıt Ayrıştırma** (`extract.py:382-428`)
|
|||
|
|
JSON dizisi beklenir: `[{"subject": "...", "predicate": "...", "object": "..."}]`
|
|||
|
|
Ontoloji alt kümesine göre doğrulanır.
|
|||
|
|
URI'lar `expand_uri()` aracılığıyla genişletilir (extract.py:473-521).
|
|||
|
|
|
|||
|
|
4. **URI Genişletme** (`extract.py:473-521`)
|
|||
|
|
Değerin `ontology_subset.classes` sözlüğünde olup olmadığını kontrol eder.
|
|||
|
|
Bulunursa, URI sınıf tanımından çıkarılır.
|
|||
|
|
Bulunmazsa, URI oluşturulur: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"`
|
|||
|
|
|
|||
|
|
### Veri Akışı Örneği
|
|||
|
|
|
|||
|
|
**Ontoloji JSON → Yükleyici → İstek:**
|
|||
|
|
```
|
|||
|
|
"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**LLM → Ayrıştırıcı → Çıktı:**
|
|||
|
|
```
|
|||
|
|
"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI
|
|||
|
|
"fo/Recipe" → found in classes → uses original URI → PRESERVES URI
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Belirlenen Sorunlar
|
|||
|
|
|
|||
|
|
### 1. **İstemde Tutarsız Örnekler**
|
|||
|
|
|
|||
|
|
**Sorun**: İstem şablonu, sınıf kimliklerini öneklerle (`fo/Recipe`) gösterirken, örnek çıktı önek kullanılmayan sınıf adlarını kullanır (`Recipe`).
|
|||
|
|
|
|||
|
|
**Konum**: `ontology-prompt.md:5-52`
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
## Ontology Classes:
|
|||
|
|
- **fo/Recipe**: A Recipe is...
|
|||
|
|
|
|||
|
|
## Example Output:
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Etki**: LLM, hangi formatı kullanması gerektiği konusunda çelişkili sinyaller alır.
|
|||
|
|
|
|||
|
|
### 2. **URI Genişletmesinde Bilgi Kaybı**
|
|||
|
|
|
|||
|
|
**Sorun**: LLM, örneğe uygun olarak önekli olmayan sınıf adları döndürdüğünde, `expand_uri()` bunları ontoloji sözlüğünde bulamaz ve yedek URI'ler oluşturur, böylece orijinal doğru URI'ler kaybolur.
|
|||
|
|
|
|||
|
|
**Konum**: `extract.py:494-500`
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
if value in ontology_subset.classes: # Looks for "Recipe"
|
|||
|
|
class_def = ontology_subset.classes[value] # But key is "fo/Recipe"
|
|||
|
|
if isinstance(class_def, dict) and 'uri' in class_def:
|
|||
|
|
return class_def['uri'] # Never reached!
|
|||
|
|
return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Etki:**
|
|||
|
|
Orijinal URI: `http://purl.org/ontology/fo/Recipe`
|
|||
|
|
Oluşturulmuş URI: `https://trustgraph.ai/ontology/food#Recipe`
|
|||
|
|
Anlamsal anlam kayboluyor, birlikte çalışabilirlik bozuluyor.
|
|||
|
|
|
|||
|
|
### 3. **Belirsiz Varlık Örneği Biçimi**
|
|||
|
|
|
|||
|
|
**Sorun:** Varlık örneği URI biçimi hakkında net bir rehberlik yok.
|
|||
|
|
|
|||
|
|
**İpuçlarındaki örnekler:**
|
|||
|
|
`"recipe:cornish-pasty"` (namespace benzeri önek)
|
|||
|
|
`"ingredient:flour"` (farklı önek)
|
|||
|
|
|
|||
|
|
**Gerçek davranış** (extract.py:517-520):
|
|||
|
|
```python
|
|||
|
|
# Treat as entity instance - construct unique URI
|
|||
|
|
normalized = value.replace(" ", "-").lower()
|
|||
|
|
return f"https://trustgraph.ai/{ontology_id}/{normalized}"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Etki**: LLM'nin, herhangi bir ontoloji bağlamı olmadan, önekleme kuralını tahmin etmesi gerekir.
|
|||
|
|
|
|||
|
|
### 4. **Ada Alanı Önekleri Hakkında Rehberlik Yok**
|
|||
|
|
|
|||
|
|
**Sorun**: Ontoloji JSON dosyası, ada alanı tanımlarını içerir (food.ontology dosyasının 10-25. satırları):
|
|||
|
|
```json
|
|||
|
|
"namespaces": {
|
|||
|
|
"fo": "http://purl.org/ontology/fo/",
|
|||
|
|
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Ancak bunlar asla LLM'ye iletilmez. LLM şunları bilmez:
|
|||
|
|
"fo" kelimesinin ne anlama geldiğini
|
|||
|
|
Varlıklar için hangi öneklerin kullanılması gerektiğini
|
|||
|
|
Hangi ad alanının hangi öğelere uygulandığını
|
|||
|
|
|
|||
|
|
### 5. **İpuçunda Kullanılmayan Etiketler**
|
|||
|
|
|
|||
|
|
**Sorun**: Her sınıfın `rdfs:label` alanları vardır (örneğin, `{"value": "Recipe", "lang": "en-gb"}`), ancak ipucu şablonu bunları kullanmaz.
|
|||
|
|
|
|||
|
|
**Mevcut durum**: Sadece `class_id` ve `comment` gösteriliyor.
|
|||
|
|
```jinja
|
|||
|
|
- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Kullanılabilir ancak kullanılmayan:**
|
|||
|
|
```python
|
|||
|
|
"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Etki**: Teknik kimliklerin yanı sıra insan tarafından okunabilir isimler sağlayabilir.
|
|||
|
|
|
|||
|
|
## Önerilen Çözümler
|
|||
|
|
|
|||
|
|
### Seçenek A: Önek Olmayan Kimliklere Normalleştirme
|
|||
|
|
|
|||
|
|
**Yaklaşım**: Sınıf kimliklerinden önekleri, LLM'ye göstermeden önce kaldırın.
|
|||
|
|
|
|||
|
|
**Değişiklikler**:
|
|||
|
|
1. `build_extraction_variables()`'ı, anahtarları dönüştürmek için değiştirin:
|
|||
|
|
```python
|
|||
|
|
classes_for_prompt = {
|
|||
|
|
k.split('/')[-1]: v # "fo/Recipe" → "Recipe"
|
|||
|
|
for k, v in ontology_subset.classes.items()
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. İstem örneğini, (zaten önek kullanmayan) mevcut duruma uygun hale getirin.
|
|||
|
|
|
|||
|
|
3. `expand_uri()`'ı, her iki formatı da işleyebilecek şekilde değiştirin:
|
|||
|
|
```python
|
|||
|
|
# Try exact match first
|
|||
|
|
if value in ontology_subset.classes:
|
|||
|
|
return ontology_subset.classes[value]['uri']
|
|||
|
|
|
|||
|
|
# Try with prefix
|
|||
|
|
for prefix in ['fo/', 'rdf:', 'rdfs:']:
|
|||
|
|
prefixed = f"{prefix}{value}"
|
|||
|
|
if prefixed in ontology_subset.classes:
|
|||
|
|
return ontology_subset.classes[prefixed]['uri']
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Artıları:**
|
|||
|
|
Daha temiz, daha insan tarafından okunabilir
|
|||
|
|
Mevcut örnek istemlerle eşleşir
|
|||
|
|
Büyük dil modelleri (LLM'ler), daha basit belirteçlerle daha iyi çalışır
|
|||
|
|
|
|||
|
|
**Eksileri:**
|
|||
|
|
Birden fazla ontolojinin aynı sınıf adına sahip olması durumunda sınıf adı çakışmaları
|
|||
|
|
Ad alanı bilgilerini kaybettirir
|
|||
|
|
Arama işlemlerinde yedekleme mantığı gerektirir
|
|||
|
|
|
|||
|
|
### B Seçeneği: Tam Önekli Kimlikleri Tutarlı Bir Şekilde Kullanın
|
|||
|
|
|
|||
|
|
**Yaklaşım:** Örnekleri, sınıf listesinde gösterilenlerle eşleşen önekli kimlikleri kullanacak şekilde güncelleyin.
|
|||
|
|
|
|||
|
|
**Değişiklikler:**
|
|||
|
|
1. Örnek istemi güncelleyin (ontology-prompt.md:46-52):
|
|||
|
|
```json
|
|||
|
|
[
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"},
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"},
|
|||
|
|
{"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"},
|
|||
|
|
{"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"}
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. İstemde (prompt) ad alanı açıklamasını ekleyin:
|
|||
|
|
```markdown
|
|||
|
|
## Namespace Prefixes:
|
|||
|
|
- **fo/**: Food Ontology (http://purl.org/ontology/fo/)
|
|||
|
|
- **rdf:**: RDF Schema
|
|||
|
|
- **rdfs:**: RDF Schema
|
|||
|
|
|
|||
|
|
Use these prefixes exactly as shown when referencing classes and properties.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. `expand_uri()`'ı olduğu gibi tutun (eşleşmeler bulunduğunda doğru şekilde çalışır).
|
|||
|
|
|
|||
|
|
**Avantajları:**
|
|||
|
|
Giriş = Çıkış tutarlılığı
|
|||
|
|
Bilgi kaybı yok
|
|||
|
|
Ada alanı semantiğini korur
|
|||
|
|
Birden fazla ontoloji ile çalışır
|
|||
|
|
|
|||
|
|
**Dezavantajları:**
|
|||
|
|
LLM için daha ayrıntılı belirteçler
|
|||
|
|
LLM'nin önekleri takip etmesini gerektirir
|
|||
|
|
|
|||
|
|
### Seçenek C: Hibrit - Hem Etiketi Hem de Kimliği Gösterin
|
|||
|
|
|
|||
|
|
**Yaklaşım:** İnsan tarafından okunabilir etiketleri ve teknik kimlikleri göstermek için istemi geliştirin.
|
|||
|
|
|
|||
|
|
**Değişiklikler:**
|
|||
|
|
1. İstem şablonunu güncelleyin:
|
|||
|
|
```jinja
|
|||
|
|
{% for class_id, class_def in classes.items() %}
|
|||
|
|
- **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %}
|
|||
|
|
{% endfor %}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Örnek çıktı:
|
|||
|
|
```markdown
|
|||
|
|
- **fo/Recipe** (label: "Recipe"): A Recipe is a combination...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. Güncelleme talimatları:
|
|||
|
|
```markdown
|
|||
|
|
When referencing classes:
|
|||
|
|
- Use the full prefixed ID (e.g., "fo/Recipe") in JSON output
|
|||
|
|
- The label (e.g., "Recipe") is for human understanding only
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Avantajları**:
|
|||
|
|
LLM için en anlaşılır olanı
|
|||
|
|
Tüm bilgileri korur
|
|||
|
|
Ne kullanılması gerektiği konusunda açık
|
|||
|
|
|
|||
|
|
**Dezavantajları**:
|
|||
|
|
Daha uzun bir istem
|
|||
|
|
Daha karmaşık bir şablon
|
|||
|
|
|
|||
|
|
## Uygulanan Yaklaşım
|
|||
|
|
|
|||
|
|
**Basitleştirilmiş Varlık-İlişki-Özellik Formatı** - eski üçlü tabanlı formatın tamamen yerini alır.
|
|||
|
|
|
|||
|
|
Bu yeni yaklaşım aşağıdaki nedenlerle seçilmiştir:
|
|||
|
|
|
|||
|
|
1. **Bilgi Kaybı Yok**: Orijinal URI'ler doğru şekilde korunur
|
|||
|
|
2. **Daha Basit Mantık**: Dönüştürmeye gerek yoktur, doğrudan sözlük aramaları çalışır
|
|||
|
|
3. **Ad Alanı Güvenliği**: Çakışmalar olmadan birden fazla ontolojiyi işler
|
|||
|
|
4. **Anlamsal Doğruluk**: RDF/OWL semantiğini korur
|
|||
|
|
|
|||
|
|
## Uygulama Tamamlandı
|
|||
|
|
|
|||
|
|
### Oluşturulanlar:
|
|||
|
|
|
|||
|
|
1. **Yeni İstek Şablonu** (`prompts/ontology-extract-v2.txt`)
|
|||
|
|
✅ Açık bölümler: Varlık Türleri, İlişkiler, Özellikler
|
|||
|
|
✅ Tam tür tanımlayıcılarını kullanan örnek (`fo/Recipe`, `fo/has_ingredient`)
|
|||
|
|
✅ Şemadan tam tanımlayıcıları kullanma talimatları
|
|||
|
|
✅ Varlıklar/ilişkiler/özellikler dizileri içeren yeni JSON formatı
|
|||
|
|
|
|||
|
|
2. **Varlık Normalizasyonu** (`entity_normalizer.py`)
|
|||
|
|
✅ `normalize_entity_name()` - İsimleri URI'ye uygun formata dönüştürür
|
|||
|
|
✅ `normalize_type_identifier()` - Türlerdeki eğik çizgileri işler (`fo/Recipe` → `fo-recipe`)
|
|||
|
|
✅ `build_entity_uri()` - (isim, tür) tuple'ını kullanarak benzersiz URI'ler oluşturur
|
|||
|
|
✅ `EntityRegistry` - Tekrarlamayı önlemek için varlıkları takip eder
|
|||
|
|
|
|||
|
|
3. **JSON Ayrıştırıcı** (`simplified_parser.py`)
|
|||
|
|
✅ Yeni formatı ayrıştırır: `{entities: [...], relationships: [...], attributes: [...]}`
|
|||
|
|
✅ kebab-case ve snake_case alan adlarını destekler
|
|||
|
|
✅ Yapılandırılmış veri sınıfları döndürür
|
|||
|
|
✅ Günlükleme ile zarif hata işleme
|
|||
|
|
|
|||
|
|
4. **Üçlü Dönüştürücü** (`triple_converter.py`)
|
|||
|
|
✅ `convert_entity()` - Tür + etiket üçlülerini otomatik olarak oluşturur
|
|||
|
|
✅ `convert_relationship()` - Varlık URI'lerini özellikler aracılığıyla bağlar
|
|||
|
|
✅ `convert_attribute()` - Literal değerleri ekler
|
|||
|
|
✅ Ontoloji tanımlarından tam URI'leri alır
|
|||
|
|
|
|||
|
|
5. **Güncellenmiş Ana İşlemci** (`extract.py`)
|
|||
|
|
✅ Eski üçlü tabanlı çıkarma kodunu kaldırdı
|
|||
|
|
✅ `extract_with_simplified_format()` yöntemini ekledi
|
|||
|
|
✅ Artık yalnızca yeni, basitleştirilmiş formatı kullanır
|
|||
|
|
✅ İstemleri `extract-with-ontologies-v2` kimliğiyle çağırır
|
|||
|
|
|
|||
|
|
## Test Senaryoları
|
|||
|
|
|
|||
|
|
### Test 1: URI Korunması
|
|||
|
|
```python
|
|||
|
|
# Given ontology class
|
|||
|
|
classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}}
|
|||
|
|
|
|||
|
|
# When LLM returns
|
|||
|
|
llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"}
|
|||
|
|
|
|||
|
|
# Then expanded URI should be
|
|||
|
|
assert expanded == "http://purl.org/ontology/fo/Recipe"
|
|||
|
|
# Not: "https://trustgraph.ai/ontology/food#Recipe"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Test 2: Çoklu Ontoloji Çakışması
|
|||
|
|
```python
|
|||
|
|
# Given two ontologies
|
|||
|
|
ont1 = {"fo/Recipe": {...}}
|
|||
|
|
ont2 = {"cooking/Recipe": {...}}
|
|||
|
|
|
|||
|
|
# LLM should use full prefix to disambiguate
|
|||
|
|
llm_output = {"object": "fo/Recipe"} # Not just "Recipe"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Test 3: Varlık Örneği Formatı
|
|||
|
|
```python
|
|||
|
|
# Given prompt with food ontology
|
|||
|
|
# LLM should create instances like
|
|||
|
|
{"subject": "recipe:cornish-pasty"} # Namespace-style
|
|||
|
|
{"subject": "food:beef"} # Consistent prefix
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Açık Sorular
|
|||
|
|
|
|||
|
|
1. **Varlık örnekleri namespace önekleri kullanmalı mı?**
|
|||
|
|
Mevcut durum: `"recipe:cornish-pasty"` (keyfi)
|
|||
|
|
Alternatif: Ontoloji önekini kullanın `"fo:cornish-pasty"`?
|
|||
|
|
Alternatif: Önek yok, URI'da genişletin `"cornish-pasty"` → tam URI?
|
|||
|
|
|
|||
|
|
2. **Alan/kapsam (domain/range) nasıl işlenmeli?**
|
|||
|
|
Şu anda gösterilen: `(Recipe → Food)`
|
|||
|
|
Şu şekilde olmalı mı: `(fo/Recipe → fo/Food)`?
|
|||
|
|
|
|||
|
|
3. **Alan/kapsam kısıtlamalarını doğrulamalı mıyız?**
|
|||
|
|
TODO yorumu extract.py:470 satırında
|
|||
|
|
Daha fazla hata yakalanır, ancak daha karmaşık olur
|
|||
|
|
|
|||
|
|
4. **Ters özellikler ve eşdeğerlikler hakkında ne düşünülmeli?**
|
|||
|
|
Ontolojide `owl:inverseOf`, `owl:equivalentClass` bulunmaktadır
|
|||
|
|
Şu anda çıkarımda kullanılmıyor
|
|||
|
|
Kullanılmalı mı?
|
|||
|
|
|
|||
|
|
## Başarı Metrikleri
|
|||
|
|
|
|||
|
|
✅ Sıfır URI bilgisi kaybı (orijinal URI'lerin %100 korunması)
|
|||
|
|
✅ LLM çıktısı formatı, giriş formatıyla eşleşiyor
|
|||
|
|
✅ Girişte belirsiz örnek yok
|
|||
|
|
✅ Birden fazla ontolojiyle testler geçiliyor
|
|||
|
|
✅ İyileştirilmiş çıkarım kalitesi (geçerli üçlü yüzdesi ile ölçülür)
|
|||
|
|
|
|||
|
|
## Alternatif Yaklaşım: Basitleştirilmiş Çıkarım Formatı
|
|||
|
|
|
|||
|
|
### Felsefe
|
|||
|
|
|
|||
|
|
LLM'den RDF/OWL semantiğini anlamasını istemek yerine, LLM'nin iyi olduğu şeyi yapmasını isteyin: **metindeki varlıkları ve ilişkileri bulun**.
|
|||
|
|
|
|||
|
|
URI oluşturma, RDF'ye dönüştürme ve semantik web formalitelerini kodun halletmesine izin verin.
|
|||
|
|
|
|||
|
|
### Örnek: Varlık Sınıflandırması
|
|||
|
|
|
|||
|
|
**Giriş Metni:**
|
|||
|
|
```
|
|||
|
|
Cornish pasty is a traditional British pastry filled with meat and vegetables.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Ontoloji Şeması (LLM'ye gösterilen):**
|
|||
|
|
```markdown
|
|||
|
|
## Entity Types:
|
|||
|
|
- Recipe: A recipe is a combination of ingredients and a method
|
|||
|
|
- Food: A food is something that can be eaten
|
|||
|
|
- Ingredient: An ingredient combines a quantity and a food
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**LLM'nin Döndürdükleri (Basit JSON):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"entities": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty",
|
|||
|
|
"type": "Recipe"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Kodun Ürettiği Şeyler (RDF Üçlüleri):**
|
|||
|
|
```python
|
|||
|
|
# 1. Normalize entity name + type to ID (type prevents collisions)
|
|||
|
|
entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe")
|
|||
|
|
entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty"
|
|||
|
|
|
|||
|
|
# Note: Same name, different type = different URI
|
|||
|
|
# "Cornish pasty" (Recipe) → recipe-cornish-pasty
|
|||
|
|
# "Cornish pasty" (Food) → food-cornish-pasty
|
|||
|
|
|
|||
|
|
# 2. Generate triples
|
|||
|
|
triples = [
|
|||
|
|
# Type triple
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=entity_uri, is_uri=True),
|
|||
|
|
p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True),
|
|||
|
|
o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True)
|
|||
|
|
),
|
|||
|
|
# Label triple (automatic)
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=entity_uri, is_uri=True),
|
|||
|
|
p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True),
|
|||
|
|
o=Value(value="Cornish pasty", is_uri=False)
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Faydalar
|
|||
|
|
|
|||
|
|
1. **LLM'nin (Büyük Dil Modeli) yapması gerekmiyor:**
|
|||
|
|
URI sözdizimini anlamak
|
|||
|
|
Tanımlayıcı önekleri oluşturmak (`recipe:`, `ingredient:`)
|
|||
|
|
`rdf:type` veya `rdfs:label` hakkında bilgi sahibi olmak
|
|||
|
|
Semantik web tanımlayıcıları oluşturmak
|
|||
|
|
|
|||
|
|
2. **LLM'nin sadece yapması gerekiyor:**
|
|||
|
|
Metindeki varlıkları bulmak
|
|||
|
|
Bunları ontoloji sınıflarına eşlemek
|
|||
|
|
İlişkileri ve özellikleri çıkarmak
|
|||
|
|
|
|||
|
|
3. **Kod şunları yönetir:**
|
|||
|
|
URI normalizasyonu ve oluşturulması
|
|||
|
|
RDF üçlü üretimi
|
|||
|
|
Otomatik etiket ataması
|
|||
|
|
İsim alanı yönetimi
|
|||
|
|
|
|||
|
|
### Neden Bu Daha İyi Çalışıyor
|
|||
|
|
|
|||
|
|
**Daha basit istem** = daha az kafa karışıklığı = daha az hata
|
|||
|
|
**Tutarlı kimlikler** = kod, normalizasyon kurallarını kontrol eder
|
|||
|
|
**Otomatik olarak oluşturulan etiketler** = eksik rdfs:label üçlüleri yok
|
|||
|
|
**LLM, çıkarma üzerine odaklanır** = aslında iyi olduğu şey
|
|||
|
|
|
|||
|
|
### Örnek: Varlık İlişkileri
|
|||
|
|
|
|||
|
|
**Giriş Metni:**
|
|||
|
|
```
|
|||
|
|
Cornish pasty is a traditional British pastry filled with beef and potatoes.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Ontoloji Şeması (LLM'ye gösterilen):**
|
|||
|
|
```markdown
|
|||
|
|
## Entity Types:
|
|||
|
|
- Recipe: A recipe is a combination of ingredients and a method
|
|||
|
|
- Food: A food is something that can be eaten
|
|||
|
|
- Ingredient: An ingredient combines a quantity and a food
|
|||
|
|
|
|||
|
|
## Relationships:
|
|||
|
|
- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient)
|
|||
|
|
- food: Relates an ingredient to the food that is required (Ingredient → Food)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**LLM'nin Döndürdükleri (Basit JSON):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"entities": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty",
|
|||
|
|
"type": "Recipe"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"entity": "beef",
|
|||
|
|
"type": "Food"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"entity": "potatoes",
|
|||
|
|
"type": "Food"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"relationships": [
|
|||
|
|
{
|
|||
|
|
"subject": "Cornish pasty",
|
|||
|
|
"subject-type": "Recipe",
|
|||
|
|
"relation": "has_ingredient",
|
|||
|
|
"object": "beef",
|
|||
|
|
"object-type": "Food"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"subject": "Cornish pasty",
|
|||
|
|
"subject-type": "Recipe",
|
|||
|
|
"relation": "has_ingredient",
|
|||
|
|
"object": "potatoes",
|
|||
|
|
"object-type": "Food"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Kodun Ürettiği Şeyler (RDF Üçlüleri):**
|
|||
|
|
```python
|
|||
|
|
# Normalize entity names to URIs
|
|||
|
|
cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty"
|
|||
|
|
beef_uri = "https://trustgraph.ai/food/beef"
|
|||
|
|
potatoes_uri = "https://trustgraph.ai/food/potatoes"
|
|||
|
|
|
|||
|
|
# Look up relation URI from ontology
|
|||
|
|
has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient
|
|||
|
|
|
|||
|
|
triples = [
|
|||
|
|
# Entity type triples (as before)
|
|||
|
|
Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"),
|
|||
|
|
Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"),
|
|||
|
|
|
|||
|
|
Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"),
|
|||
|
|
Triple(s=beef_uri, p=rdfs_label, o="beef"),
|
|||
|
|
|
|||
|
|
Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"),
|
|||
|
|
Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"),
|
|||
|
|
|
|||
|
|
# Relationship triples
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=cornish_pasty_uri, is_uri=True),
|
|||
|
|
p=Value(value=has_ingredient_uri, is_uri=True),
|
|||
|
|
o=Value(value=beef_uri, is_uri=True)
|
|||
|
|
),
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=cornish_pasty_uri, is_uri=True),
|
|||
|
|
p=Value(value=has_ingredient_uri, is_uri=True),
|
|||
|
|
o=Value(value=potatoes_uri, is_uri=True)
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Önemli Noktalar:**
|
|||
|
|
LLM, doğal dil varlık isimlerini döndürür: `"Cornish pasty"`, `"beef"`, `"potatoes"`
|
|||
|
|
LLM, anlam belirsizliğini gidermek için türleri içerir: `subject-type`, `object-type`
|
|||
|
|
LLM, şemadan ilişki adını kullanır: `"has_ingredient"`
|
|||
|
|
Kod, (isim, tür) kullanarak tutarlı kimlikler türetir: `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty`
|
|||
|
|
Kod, ontolojiden ilişki URI'sini arar: `fo/has_ingredient` → tam URI
|
|||
|
|
Aynı (isim, tür) ikilisi her zaman aynı URI'yi alır (çiftleme önleme)
|
|||
|
|
|
|||
|
|
### Örnek: Varlık İsimlerinin Anlam Belirsizliğinin Giderilmesi
|
|||
|
|
|
|||
|
|
**Sorun:** Aynı isim, farklı varlık türlerini ifade edebilir.
|
|||
|
|
|
|||
|
|
**Gerçek dünya örneği:**
|
|||
|
|
```
|
|||
|
|
"Cornish pasty" can be:
|
|||
|
|
- A Recipe (instructions for making it)
|
|||
|
|
- A Food (the dish itself)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Nasıl İşlendiği:**
|
|||
|
|
|
|||
|
|
LLM, her ikisini de ayrı varlıklar olarak döndürür:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"entities": [
|
|||
|
|
{"entity": "Cornish pasty", "type": "Recipe"},
|
|||
|
|
{"entity": "Cornish pasty", "type": "Food"}
|
|||
|
|
],
|
|||
|
|
"relationships": [
|
|||
|
|
{
|
|||
|
|
"subject": "Cornish pasty",
|
|||
|
|
"subject-type": "Recipe",
|
|||
|
|
"relation": "produces",
|
|||
|
|
"object": "Cornish pasty",
|
|||
|
|
"object-type": "Food"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Kod Çözümleme:**
|
|||
|
|
```python
|
|||
|
|
# Different types → different URIs
|
|||
|
|
recipe_uri = normalize("Cornish pasty", "Recipe")
|
|||
|
|
# → "https://trustgraph.ai/food/recipe-cornish-pasty"
|
|||
|
|
|
|||
|
|
food_uri = normalize("Cornish pasty", "Food")
|
|||
|
|
# → "https://trustgraph.ai/food/food-cornish-pasty"
|
|||
|
|
|
|||
|
|
# Relationship connects them correctly
|
|||
|
|
triple = Triple(
|
|||
|
|
s=recipe_uri, # The Recipe
|
|||
|
|
p="http://purl.org/ontology/fo/produces",
|
|||
|
|
o=food_uri # The Food
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Neden İşe Yarıyor:**
|
|||
|
|
Tip, TÜM referanslarda (varlıklar, ilişkiler, özellikler) bulunur.
|
|||
|
|
Kod, arama anahtarı olarak `(name, type)` tuple'ını kullanır.
|
|||
|
|
Herhangi bir belirsizlik, herhangi bir çakışma yoktur.
|
|||
|
|
|
|||
|
|
### Örnek: Varlık Özellikleri
|
|||
|
|
|
|||
|
|
**Giriş Metni:**
|
|||
|
|
```
|
|||
|
|
This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Ontoloji Şeması (LLM'ye gösterilen):**
|
|||
|
|
```markdown
|
|||
|
|
## Entity Types:
|
|||
|
|
- Recipe: A recipe is a combination of ingredients and a method
|
|||
|
|
|
|||
|
|
## Attributes:
|
|||
|
|
- serves: Indicates what the recipe is intended to serve (Recipe → text)
|
|||
|
|
- preparation_time: Time needed to prepare the recipe (Recipe → text)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**LLM'nin Döndürdükleri (Basit JSON):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"entities": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty recipe",
|
|||
|
|
"type": "Recipe"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"attributes": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty recipe",
|
|||
|
|
"entity-type": "Recipe",
|
|||
|
|
"attribute": "serves",
|
|||
|
|
"value": "4-6 people"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty recipe",
|
|||
|
|
"entity-type": "Recipe",
|
|||
|
|
"attribute": "preparation_time",
|
|||
|
|
"value": "45 minutes"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Kodun Ürettiği Şeyler (RDF Üçlüleri):**
|
|||
|
|
```python
|
|||
|
|
# Normalize entity name to URI
|
|||
|
|
recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe"
|
|||
|
|
|
|||
|
|
# Look up attribute URIs from ontology
|
|||
|
|
serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves
|
|||
|
|
prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time
|
|||
|
|
|
|||
|
|
triples = [
|
|||
|
|
# Entity type triple
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=recipe_uri, is_uri=True),
|
|||
|
|
p=Value(value=rdf_type, is_uri=True),
|
|||
|
|
o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True)
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# Label triple (automatic)
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=recipe_uri, is_uri=True),
|
|||
|
|
p=Value(value=rdfs_label, is_uri=True),
|
|||
|
|
o=Value(value="Cornish pasty recipe", is_uri=False)
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# Attribute triples (objects are literals, not URIs)
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=recipe_uri, is_uri=True),
|
|||
|
|
p=Value(value=serves_uri, is_uri=True),
|
|||
|
|
o=Value(value="4-6 people", is_uri=False) # Literal value!
|
|||
|
|
),
|
|||
|
|
Triple(
|
|||
|
|
s=Value(value=recipe_uri, is_uri=True),
|
|||
|
|
p=Value(value=prep_time_uri, is_uri=True),
|
|||
|
|
o=Value(value="45 minutes", is_uri=False) # Literal value!
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Önemli Noktalar:**
|
|||
|
|
LLM, gerçek değerleri çıkarır: `"4-6 people"`, `"45 minutes"`
|
|||
|
|
LLM, anlam ayrımı için varlık türünü içerir: `entity-type`
|
|||
|
|
LLM, şemadan öznitelik adını kullanır: `"serves"`, `"preparation_time"`
|
|||
|
|
Kod, öznitelik URI'sini ontoloji veri türü özelliklerinden arar
|
|||
|
|
**Nesne bir literaldir** (`is_uri=False`), bir URI referansı değildir
|
|||
|
|
Değerler, doğal metin olarak kalır, normalleştirmeye gerek yoktur
|
|||
|
|
|
|||
|
|
**İlişkilerden Farkı:**
|
|||
|
|
İlişkiler: hem konu hem de nesne varlıklardır (URI'ler)
|
|||
|
|
Öznitelikler: konu bir varlıktır (URI), nesne bir literal değerdir (dize/sayı)
|
|||
|
|
|
|||
|
|
### Tam Örnek: Varlıklar + İlişkiler + Öznitelikler
|
|||
|
|
|
|||
|
|
**Giriş Metni:**
|
|||
|
|
```
|
|||
|
|
Cornish pasty is a savory pastry filled with beef and potatoes.
|
|||
|
|
This recipe serves 4 people.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**LLM'nin Döndürdükleri:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"entities": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty",
|
|||
|
|
"type": "Recipe"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"entity": "beef",
|
|||
|
|
"type": "Food"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"entity": "potatoes",
|
|||
|
|
"type": "Food"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"relationships": [
|
|||
|
|
{
|
|||
|
|
"subject": "Cornish pasty",
|
|||
|
|
"subject-type": "Recipe",
|
|||
|
|
"relation": "has_ingredient",
|
|||
|
|
"object": "beef",
|
|||
|
|
"object-type": "Food"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"subject": "Cornish pasty",
|
|||
|
|
"subject-type": "Recipe",
|
|||
|
|
"relation": "has_ingredient",
|
|||
|
|
"object": "potatoes",
|
|||
|
|
"object-type": "Food"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"attributes": [
|
|||
|
|
{
|
|||
|
|
"entity": "Cornish pasty",
|
|||
|
|
"entity-type": "Recipe",
|
|||
|
|
"attribute": "serves",
|
|||
|
|
"value": "4 people"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Sonuç:** 11 RDF üçlüsü oluşturuldu:
|
|||
|
|
3 varlık türü üçlüsü (rdf:type)
|
|||
|
|
3 varlık etiket üçlüsü (rdfs:label) - otomatik
|
|||
|
|
2 ilişki üçlüsü (has_ingredient)
|
|||
|
|
1 özellik üçlüsü (serves)
|
|||
|
|
|
|||
|
|
Bunların hepsi, LLM tarafından yapılan basit, doğal dil çıkarımlarından elde edilmiştir!
|
|||
|
|
|
|||
|
|
## Referanslar
|
|||
|
|
|
|||
|
|
Mevcut uygulama: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`
|
|||
|
|
İstek şablonu: `ontology-prompt.md`
|
|||
|
|
Test senaryoları: `tests/unit/test_extract/test_ontology/`
|
|||
|
|
Örnek ontoloji: `e2e/test-data/food.ontology`
|