feat: 添加线索引擎、NLQ、场景检测、前端界面等核心功能模块
This commit is contained in:
@@ -0,0 +1,360 @@
|
||||
"""主数据适配器:将源明细中的主数据表映射到本体 Entity 层。
|
||||
|
||||
覆盖:SrcCustomer / SrcSupplier / SrcEmployee / SrcChannel / SrcMsisdn / SrcAccount
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.datahub.graph_repo import add_relationship, upsert_entity
|
||||
from app.datahub.ontology import EntityType, RelationshipType
|
||||
from app.datahub.staging import (
|
||||
SrcAccount,
|
||||
SrcChannel,
|
||||
SrcCustomer,
|
||||
SrcEmployee,
|
||||
SrcMsisdn,
|
||||
SrcSupplier,
|
||||
)
|
||||
from app.ingest.base import BaseAdapter, IngestResult
|
||||
from app.ingest.registry import register_adapter
|
||||
|
||||
|
||||
@register_adapter
|
||||
class CustomerAdapter(BaseAdapter):
|
||||
"""SrcCustomer → Entity(CUSTOMER) + 关系(REGISTERED_AT, LEGAL_REP_OF)。"""
|
||||
|
||||
source_system = "BSS"
|
||||
staging_table = "src_customer"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcCustomer).filter(
|
||||
SrcCustomer.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcCustomer).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CUSTOMER,
|
||||
business_key=row.customer_key,
|
||||
display_name=row.customer_name,
|
||||
attributes={
|
||||
"customer_type": row.customer_type,
|
||||
"uscc": row.uscc,
|
||||
"open_date": str(row.open_date) if row.open_date else None,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(entity)
|
||||
|
||||
# 注册地址 → Entity(ADDRESS) + 关系 REGISTERED_AT
|
||||
if row.register_address:
|
||||
addr_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ADDRESS,
|
||||
business_key=row.register_address,
|
||||
display_name=row.register_address,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(addr_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.REGISTERED_AT, entity, addr_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
# 法人 → Entity(LEGAL_PERSON) + 关系 LEGAL_REP_OF
|
||||
if row.legal_person:
|
||||
lp_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.LEGAL_PERSON,
|
||||
business_key=row.legal_person,
|
||||
display_name=row.legal_person,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(lp_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.LEGAL_REP_OF, lp_entity, entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class SupplierAdapter(BaseAdapter):
|
||||
"""SrcSupplier → Entity(SUPPLIER) + 关系(REGISTERED_AT, LEGAL_REP_OF)。"""
|
||||
|
||||
source_system = "ERP"
|
||||
staging_table = "src_supplier"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcSupplier).filter(
|
||||
SrcSupplier.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcSupplier).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.SUPPLIER,
|
||||
business_key=row.supplier_key,
|
||||
display_name=row.supplier_name,
|
||||
attributes={
|
||||
"uscc": row.uscc,
|
||||
"shareholder_info": row.shareholder_info,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(entity)
|
||||
|
||||
if row.register_address:
|
||||
addr_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ADDRESS,
|
||||
business_key=row.register_address,
|
||||
display_name=row.register_address,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(addr_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.REGISTERED_AT, entity, addr_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
if row.legal_person:
|
||||
lp_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.LEGAL_PERSON,
|
||||
business_key=row.legal_person,
|
||||
display_name=row.legal_person,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(lp_entity)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.LEGAL_REP_OF, lp_entity, entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class EmployeeAdapter(BaseAdapter):
|
||||
"""SrcEmployee → Entity(EMPLOYEE)。"""
|
||||
|
||||
source_system = "ERP"
|
||||
staging_table = "src_employee"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcEmployee).filter(
|
||||
SrcEmployee.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcEmployee).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.EMPLOYEE,
|
||||
business_key=row.employee_key,
|
||||
display_name=row.employee_name,
|
||||
attributes={
|
||||
"position": row.position,
|
||||
"department": row.department,
|
||||
"role_permissions": row.role_permissions,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class ChannelAdapter(BaseAdapter):
|
||||
"""SrcChannel → Entity(CHANNEL)。"""
|
||||
|
||||
source_system = "BSS"
|
||||
staging_table = "src_channel"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcChannel).filter(
|
||||
SrcChannel.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcChannel).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CHANNEL,
|
||||
business_key=row.channel_key,
|
||||
display_name=row.channel_name,
|
||||
attributes={
|
||||
"commission_policy": row.commission_policy,
|
||||
"region": row.region,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class MsisdnAdapter(BaseAdapter):
|
||||
"""SrcMsisdn → Entity(MSISDN) + 关系(HOLDS_MSISDN)。"""
|
||||
|
||||
source_system = "BSS"
|
||||
staging_table = "src_msisdn"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcMsisdn).filter(
|
||||
SrcMsisdn.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcMsisdn).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
msisdn_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.MSISDN,
|
||||
business_key=row.msisdn,
|
||||
display_name=row.msisdn,
|
||||
attributes={
|
||||
"region": row.region,
|
||||
"status": row.status,
|
||||
"activate_date": str(row.activate_date) if row.activate_date else None,
|
||||
"deactivate_date": str(row.deactivate_date) if row.deactivate_date else None,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(msisdn_entity)
|
||||
|
||||
# 号码 → 客户持有关系
|
||||
if row.customer_key:
|
||||
cust_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.CUSTOMER,
|
||||
business_key=row.customer_key,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.HOLDS_MSISDN, cust_entity, msisdn_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@register_adapter
|
||||
class AccountAdapter(BaseAdapter):
|
||||
"""SrcAccount → Entity(ACCOUNT) + 关系(OWNS_ACCOUNT)。"""
|
||||
|
||||
source_system = "FIN"
|
||||
staging_table = "src_account"
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
session: Session,
|
||||
data_version_id: uuid.UUID | None = None,
|
||||
batch_size: int = 1000,
|
||||
) -> IngestResult:
|
||||
result = IngestResult()
|
||||
rows = session.query(SrcAccount).filter(
|
||||
SrcAccount.data_version_id == data_version_id
|
||||
).limit(batch_size).all() if data_version_id else session.query(SrcAccount).limit(batch_size).all()
|
||||
|
||||
for row in rows:
|
||||
try:
|
||||
acct_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=EntityType.ACCOUNT,
|
||||
business_key=row.account_key,
|
||||
display_name=row.account_name,
|
||||
attributes={
|
||||
"bank_name": row.bank_name,
|
||||
"branch_name": row.branch_name,
|
||||
},
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.entities.append(acct_entity)
|
||||
|
||||
# 账户所属主体关系
|
||||
if row.owner_key and row.owner_type:
|
||||
owner_type_map = {
|
||||
"customer": EntityType.CUSTOMER,
|
||||
"supplier": EntityType.SUPPLIER,
|
||||
"legal_person": EntityType.LEGAL_PERSON,
|
||||
}
|
||||
etype = owner_type_map.get(row.owner_type)
|
||||
if etype:
|
||||
owner_entity = upsert_entity(
|
||||
session,
|
||||
entity_type=etype,
|
||||
business_key=row.owner_key,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
rel = add_relationship(
|
||||
session, RelationshipType.OWNS_ACCOUNT, owner_entity, acct_entity,
|
||||
data_version_id=data_version_id,
|
||||
)
|
||||
result.relationships.append(rel)
|
||||
|
||||
result.row_count += 1
|
||||
except Exception:
|
||||
result.error_count += 1
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user