|
|
|
|
|
import networkx as nx
|
|
import pandas as pd
|
|
import logging
|
|
|
|
|
|
from src.data_management import storage
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
|
|
GRAPH_FILENAME = "concept_network"
|
|
|
|
|
|
SIMILARITY_FILENAME = "concept_similarities"
|
|
|
|
def build_concept_network(similarity_threshold: float = 0.60,
|
|
include_similarity_edges: bool = True,
|
|
include_extracted_edges: bool = True) -> nx.Graph | None:
|
|
"""
|
|
Konseptler, çıkarılmış ilişkiler ve anlamsal benzerliklerden bir NetworkX grafı oluşturur.
|
|
|
|
Args:
|
|
similarity_threshold (float): Grafiğe eklenecek minimum anlamsal benzerlik skoru.
|
|
include_similarity_edges (bool): Benzerlik kenarlarını dahil et.
|
|
include_extracted_edges (bool): Metinden çıkarılan ilişki kenarlarını dahil et.
|
|
|
|
Returns:
|
|
nx.Graph | None: Oluşturulan NetworkX grafı veya hata durumunda None.
|
|
"""
|
|
logging.info("Konsept ağı oluşturuluyor...")
|
|
if not include_similarity_edges and not include_extracted_edges:
|
|
logging.warning("Hem benzerlik hem de çıkarılmış ilişki kenarları devre dışı bırakıldı.")
|
|
|
|
|
|
concepts_df = storage.load_dataframe('concepts', storage.CONCEPT_COLUMNS)
|
|
relationships_df = storage.load_dataframe('relationships', storage.RELATIONSHIP_COLUMNS)
|
|
|
|
similarity_df = storage.load_dataframe(SIMILARITY_FILENAME, ['concept_id_1', 'concept_id_2', 'similarity'])
|
|
|
|
if concepts_df is None or concepts_df.empty:
|
|
logging.error("Ağ oluşturmak için konsept verisi bulunamadı.")
|
|
return None
|
|
|
|
G = nx.Graph()
|
|
|
|
|
|
node_count = 0
|
|
valid_concept_ids = set()
|
|
for index, row in concepts_df.iterrows():
|
|
concept_id = row['concept_id']
|
|
concept_name = row['name']
|
|
if pd.notna(concept_id) and pd.notna(concept_name):
|
|
G.add_node(concept_id, name=concept_name)
|
|
valid_concept_ids.add(concept_id)
|
|
node_count += 1
|
|
else:
|
|
logging.warning(f"Geçersiz konsept verisi atlandı: ID={concept_id}, Name={concept_name}")
|
|
logging.info(f"{node_count} konsept düğüm olarak eklendi.")
|
|
|
|
edge_count_extracted = 0
|
|
edge_count_similarity = 0
|
|
updated_edge_count = 0
|
|
|
|
|
|
if include_extracted_edges and relationships_df is not None and not relationships_df.empty:
|
|
logging.info("Çıkarılmış ilişkiler kenar olarak ekleniyor...")
|
|
for index, row in relationships_df.iterrows():
|
|
source_id = row['source_concept_id']
|
|
target_id = row['target_concept_id']
|
|
rel_type = row['type'] or 'RELATED_TO'
|
|
|
|
|
|
if source_id in valid_concept_ids and target_id in valid_concept_ids:
|
|
if G.has_edge(source_id, target_id):
|
|
G.edges[source_id, target_id]['relation_type'] = rel_type
|
|
G.edges[source_id, target_id]['type'] = 'extracted'
|
|
else:
|
|
G.add_edge(source_id, target_id, type='extracted', relation_type=rel_type, weight=0.8)
|
|
edge_count_extracted += 1
|
|
else:
|
|
logging.warning(f"İlişki için düğüm(ler) bulunamadı veya geçersiz: {source_id} -> {target_id}")
|
|
logging.info(f"{edge_count_extracted} çıkarılmış ilişki kenarı eklendi.")
|
|
|
|
|
|
if include_similarity_edges and similarity_df is not None and not similarity_df.empty:
|
|
logging.info(f"Anlamsal benzerlikler (Eşik > {similarity_threshold:.2f}) kenar olarak ekleniyor...")
|
|
filtered_similarity = similarity_df[(similarity_df['similarity'] >= similarity_threshold) & (similarity_df['similarity'] < 1.0)]
|
|
logging.info(f"{len(similarity_df)} benzerlik çiftinden {len(filtered_similarity)} tanesi eşik değerinin üzerinde (ve < 1.0).")
|
|
|
|
for index, row in filtered_similarity.iterrows():
|
|
id1 = row['concept_id_1']
|
|
id2 = row['concept_id_2']
|
|
similarity = row['similarity']
|
|
|
|
if id1 in valid_concept_ids and id2 in valid_concept_ids:
|
|
if G.has_edge(id1, id2):
|
|
G.edges[id1, id2]['similarity'] = similarity
|
|
if 'weight' not in G.edges[id1, id2] or similarity > G.edges[id1, id2].get('weight', 0):
|
|
G.edges[id1, id2]['weight'] = similarity
|
|
|
|
G.edges[id1, id2]['type'] = 'combined' if G.edges[id1, id2].get('type') == 'extracted' else G.edges[id1, id2].get('type', 'similarity')
|
|
updated_edge_count += 1
|
|
else:
|
|
G.add_edge(id1, id2, type='similarity', weight=similarity)
|
|
edge_count_similarity += 1
|
|
else:
|
|
logging.warning(f"Benzerlik için düğüm(ler) bulunamadı veya geçersiz: {id1} <-> {id2}")
|
|
logging.info(f"{edge_count_similarity} yeni benzerlik kenarı eklendi, {updated_edge_count} mevcut kenara benzerlik/tip bilgisi eklendi.")
|
|
|
|
total_edges = G.number_of_edges()
|
|
logging.info(f"Konsept ağı oluşturuldu. Düğüm sayısı: {G.number_of_nodes()}, Kenar sayısı: {total_edges}.")
|
|
|
|
|
|
storage.save_network(G, GRAPH_FILENAME)
|
|
|
|
return G |