openclaw 网盘下载
OpenClaw

技能详情(站内镜像,无评论)

首页 > 技能库 > Ontology Mapper

Map construction data to standard ontologies. Create semantic mappings between different data schemas

数据与表格

许可证:MIT-0

MIT-0 ·免费使用、修改和重新分发。无需归因。

版本:v2.1.0

统计:⭐ 0 · 1.1k · 12 current installs · 13 all-time installs

0

安装量(当前) 13

🛡 VirusTotal :可疑 · OpenClaw :良性

Package:datadrivenconstruction/ontology-mapper

安全扫描(ClawHub)

  • VirusTotal :可疑
  • OpenClaw :良性

OpenClaw 评估

The skill is internally consistent with its stated purpose (mapping construction data to standard ontologies); it requires python and filesystem access which align with processing user-provided files, and there are no unexpected credentials, network endpoints, or install steps.

目的

Name/description (ontology mapping) align with the declared requirements: python3 is required and the SKILL.md contains Python-based mapping classes and logic. Requesting filesystem access in claw.json is reasonable for reading user-supplied CSV/Excel/JSON files.

说明范围

instructions.md and SKILL.md focus on processing data the user supplies and producing mapping reports. The skill documentation explicitly constrains operations to user-provided data, but the claw.json grants generic filesystem permission—this is required for file-based inputs but means the skill could read files if misused. No instructions were found that direct the agent to read unrelated system files or environment secrets.

安装机制

There is no install spec and no code files to write/execute on install (instruction-only). This minimizes installation risk. The only runtime requirement is python3, which matches the provided code examples.

证书

The skill declares no required environment variables or credentials. That is proportional to the described task of local data mapping. No evidence in the provided files of attempts to access unrelated credentials or external services.

持久

always is false (normal) and disable-model-invocation is false (normal autonomous invocation). claw.json includes a broad 'filesystem' permission which is appropriate for reading input files but is a sensitive permission—users should avoid supplying sensitive system files. The skill does not request persistent system-wide privileges.

综合结论

This skill appears to do what it says: map construction data to ontologies using Python and reading user-provided files. Before installing or invoking it, only give it the files you want processed (avoid sending system or credential files), confirm the homepage/owner if provenance matters, and prefer manual review of any exported mappings before sharing them externally. Because the package requests filesystem access in its metadata, treat that…

安装(复制给龙虾 AI)

将下方整段复制到龙虾中文库对话中,由龙虾按 SKILL.md 完成安装。

请把本段交给龙虾中文库(龙虾 AI)执行:为本机安装 OpenClaw 技能「Ontology Mapper」。简介:Map construction data to standard ontologies. Create semantic mappings between …。
请 fetch 以下地址读取 SKILL.md 并按文档完成安装:https://raw.githubusercontent.com/openclaw/skills/refs/heads/main/skills/datadrivenconstruction/ontology-mapper/SKILL.md
(来源:yingzhi8.cn 技能库)

SKILL.md

打开原始 SKILL.md(GitHub raw)

---
name: "ontology-mapper"
description: "Map construction data to standard ontologies. Create semantic mappings between different data schemas"
homepage: "https://datadrivenconstruction.io"
metadata: {"openclaw": {"emoji": "🌐", "os": ["darwin", "linux", "win32"], "homepage": "https://datadrivenconstruction.io", "requires": {"bins": ["python3"]}}}
---
# Ontology Mapper

## Overview

Based on DDC methodology (Chapter 2.2), this skill maps construction data to standard ontologies like IFC, COBie, Uniclass, and OmniClass, enabling semantic interoperability between systems.

**Book Reference:** "Доминирование открытых данных" / "Open Data Dominance"

## Quick Start

```python
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Dict, Optional, Set, Tuple
from datetime import datetime
import json
import re

class OntologyType(Enum):
    """Standard construction ontologies"""
    IFC = "ifc"                    # Industry Foundation Classes
    COBIE = "cobie"                # Construction Operations Building Information Exchange
    UNICLASS = "uniclass"          # UK classification
    OMNICLASS = "omniclass"        # North American classification
    MASTERFORMAT = "masterformat"  # CSI MasterFormat
    UNIFORMAT = "uniformat"        # CSI UniFormat
    CUSTOM = "custom"              # Custom ontology

class MappingConfidence(Enum):
    """Confidence level of mapping"""
    EXACT = "exact"        # 100% match
    HIGH = "high"          # 90%+ match
    MEDIUM = "medium"      # 70-90% match
    LOW = "low"            # 50-70% match
    UNCERTAIN = "uncertain" # <50% match

class RelationType(Enum):
    """Types of relationships between concepts"""
    EQUIVALENT = "equivalent"     # Same concept
    BROADER = "broader"           # Source is more specific
    NARROWER = "narrower"         # Source is more general
    RELATED = "related"           # Related but not equivalent
    PART_OF = "part_of"           # Component relationship
    HAS_PART = "has_part"         # Contains components

@dataclass
class OntologyConcept:
    """Concept in an ontology"""
    id: str
    name: str
    ontology: OntologyType
    definition: Optional[str] = None
    parent_id: Optional[str] = None
    synonyms: List[str] = field(default_factory=list)
    properties: Dict[str, str] = field(default_factory=dict)

@dataclass
class SemanticMapping:
    """Mapping between two concepts"""
    source_concept: str
    source_ontology: OntologyType
    target_concept: str
    target_ontology: OntologyType
    relation: RelationType
    confidence: MappingConfidence
    notes: Optional[str] = None
    created_by: str = "auto"
    created_at: datetime = field(default_factory=datetime.now)

@dataclass
class MappingResult:
    """Result of ontology mapping operation"""
    source_field: str
    source_value: str
    mappings: List[SemanticMapping]
    best_match: Optional[SemanticMapping] = None
    unmapped: bool = False

@dataclass
class OntologyMappingReport:
    """Complete mapping report"""
    total_fields: int
    mapped_fields: int
    unmapped_fields: int
    mappings: List[MappingResult]
    coverage: float
    confidence_distribution: Dict[str, int]
    recommendations: List[str]


class OntologyMapper:
    """
    Map construction data to standard ontologies.
    Based on DDC methodology Chapter 2.2.
    """

    def __init__(self):
        self.ontologies = self._load_ontologies()
        self.mapping_rules = self._load_mapping_rules()
        self.synonym_map = self._build_synonym_map()

    def _load_ontologies(self) -> Dict[OntologyType, Dict[str, OntologyConcept]]:
        """Load standard construction ontologies"""
        ontologies = {}

        # IFC Schema (simplified)
        ontologies[OntologyType.IFC] = {
            "IfcWall": OntologyConcept("IfcWall", "Wall", OntologyType.IFC,
                "A vertical construction that bounds or subdivides spaces"),
            "IfcSlab": OntologyConcept("IfcSlab", "Slab", OntologyType.IFC,
                "A horizontal planar building element"),
            "IfcBeam": OntologyConcept("IfcBeam", "Beam", OntologyType.IFC,
                "A horizontal structural member"),
            "IfcColumn": OntologyConcept("IfcColumn", "Column", OntologyType.IFC,
                "A vertical structural member"),
            "IfcDoor": OntologyConcept("IfcDoor", "Door", OntologyType.IFC,
                "A building element for access"),
            "IfcWindow": OntologyConcept("IfcWindow", "Window", OntologyType.IFC,
                "A building element for light and ventilation"),
            "IfcRoof": OntologyConcept("IfcRoof", "Roof", OntologyType.IFC,
                "A building element covering a building"),
            "IfcStair": OntologyConcept("IfcStair", "Stair", OntologyType.IFC,
                "A vertical circulation element"),
            "IfcSpace": OntologyConcept("IfcSpace", "Space", OntologyType.IFC,
                "A defined volume of air"),
            "IfcBuildingStorey": OntologyConcept("IfcBuildingStorey", "Building Storey",
                OntologyType.IFC, "A horizontal aggregation of spaces"),
        }

        # COBie (simplified)
        ontologies[OntologyType.COBIE] = {
            "Floor": OntologyConcept("Floor", "Floor", OntologyType.COBIE,
                "A floor or level in a building"),
            "Space": OntologyConcept("Space", "Space", OntologyType.COBIE,
                "A spatial region"),
            "Type": OntologyConcept("Type", "Type", OntologyType.COBIE,
                "A product type or specification"),
            "Component": OntologyConcept("Component", "Component", OntologyType.COBIE,
                "An individual product instance"),
            "Zone": OntologyConcept("Zone", "Zone", OntologyType.COBIE,
                "A spatial grouping of spaces"),
            "System": OntologyConcept("System", "System", OntologyType.COBIE,
                "A building system or network"),
        }

        # Uniclass (simplified)
        ontologies[OntologyType.UNICLASS] = {
            "Ss_25": OntologyConcept("Ss_25", "Wall Systems", OntologyType.UNICLASS),
            "Ss_30": OntologyConcept("Ss_30", "Roof Systems", OntologyType.UNICLASS),
            "Ss_32": OntologyConcept("Ss_32", "Floor Systems", OntologyType.UNICLASS),
            "Ss_35": OntologyConcept("Ss_35", "Stair Systems", OntologyType.UNICLASS),
            "Pr_20": OntologyConcept("Pr_20", "Structural Products", OntologyType.UNICLASS),
            "Pr_30": OntologyConcept("Pr_30", "Wall Products", OntologyType.UNICLASS),
            "Pr_35": OntologyConcept("Pr_35", "Door Products", OntologyType.UNICLASS),
            "Pr_40": OntologyConcept("Pr_40", "Window Products", OntologyType.UNICLASS),
        }

        # MasterFormat (simplified)
        ontologies[OntologyType.MASTERFORMAT] = {
            "03": OntologyConcept("03", "Concrete", OntologyType.MASTERFORMAT),
            "04": OntologyConcept("04", "Masonry", OntologyType.MASTERFORMAT),
            "05": OntologyConcept("05", "Metals", OntologyType.MASTERFORMAT),
            "06": OntologyConcept("06", "Wood and Plastics", OntologyType.MASTERFORMAT),
            "07": OntologyConcept("07", "Thermal and Moisture Protection", OntologyType.MASTERFORMAT),
            "08": OntologyConcept("08", "Doors and Windows", OntologyType.MASTERFORMAT),
            "09": OntologyConcept("09", "Finishes", OntologyType.MASTERFORMAT),
            "22": OntologyConcept("22", "Plumbing", OntologyType.MASTERFORMAT),
            "23": OntologyConcept("23", "HVAC", OntologyType.MASTERFORMAT),
            "26": OntologyConcept("26", "Electrical", OntologyType.MASTERFORMAT),
        }

        return ontologies

    def _load_mapping_rules(self) -> List[SemanticMapping]:
        """Load predefined mapping rules between ontologies"""
        rules = [
            # IFC to COBie
            SemanticMapping("IfcBuildingStorey", OntologyType.IFC, "Floor",
                OntologyType.COBIE, RelationType.EQUIVALENT, MappingConfidence.EXACT),
            SemanticMapping("IfcSpace", OntologyType.IFC, "Space",
                OntologyType.COBIE, RelationType.EQUIVALENT, MappingConfidence.EXACT),

            # IFC to Uniclass
            SemanticMapping("IfcWall", OntologyType.IFC, "Ss_25",
                OntologyType.UNICLASS, RelationType.RELATED, MappingConfidence.HIGH),
            SemanticMapping("IfcRoof", OntologyType.IFC, "Ss_30",
                OntologyType.UNICLASS, RelationType.RELATED, MappingConfidence.HIGH),
            SemanticMapping("IfcSlab", OntologyType.IFC, "Ss_32",
                OntologyType.UNICLASS, RelationType.RELATED, MappingConfidence.HIGH),
            SemanticMapping("IfcDoor", OntologyType.IFC, "Pr_35",
                OntologyType.UNICLASS, RelationType.RELATED, MappingConfidence.HIGH),
            SemanticMapping("IfcWindow", OntologyType.IFC, "Pr_40",
                OntologyType.UNICLASS, RelationType.RELATED, MappingConfidence.HIGH),

            # IFC to MasterFormat
            SemanticMapping("IfcDoor", OntologyType.IFC, "08",
                OntologyType.MASTERFORMAT, RelationType.BROADER, MappingConfidence.MEDIUM),
            SemanticMapping("IfcWindow", OntologyType.IFC, "08",
                OntologyType.MASTERFORMAT, RelationType.BROADER, MappingConfidence.MEDIUM),
        ]
        return rules

    def _build_synonym_map(self) -> Dict[str, List[str]]:
        """Build synonym mappings for fuzzy matching"""
        return {
            "wall": ["partition", "barrier", "divider"],
            "door": ["entrance", "portal", "opening"],
            "window": ["glazing", "fenestration", "opening"],
            "floor": ["slab", "deck", "storey", "level"],
            "roof": ["roofing", "covering", "canopy"],
            "beam": ["girder", "joist", "lintel"],
            "column": ["pillar", "post", "pier"],
            "stair": ["stairway", "staircase", "steps"],
            "space": ["room", "area", "zone"],
            "concrete": ["cement", "reinforced"],
            "steel": ["metal", "iron"],
        }

    def map_field(
        self,
        field_name: str,
        field_value: str,
        source_ontology: Optional[OntologyType] = None,
        target_ontology: OntologyType = OntologyType.IFC
    ) -> MappingResult:
        """
        Map a single field to target ontology.

        Args:
            field_name: Name of the field
            field_value: Value to map
            source_ontology: Source ontology if known
            target_ontology: Target ontology to map to

        Returns:
            Mapping result with possible matches
        """
        mappings = []

        # Normalize the value
        normalized = self._normalize_value(field_value)

        # Check direct matches in existing rules
        for rule in self.mapping_rules:
            if rule.target_ontology == target_ontology:
                if self._matches(normalized, rule.source_concept):
                    mappings.append(rule)

        # Check target ontology directly
        target_concepts = self.ontologies.get(target_ontology, {})
        for concept_id, concept in target_concepts.items():
            similarity = self._calculate_similarity(normalized, concept)
            if similarity > 0.5:
                confidence = self._similarity_to_confidence(similarity)
                mappings.append(SemanticMapping(
                    source_concept=field_value,
                    source_ontology=source_ontology or OntologyType.CUSTOM,
                    target_concept=concept_id,
                    target_ontology=target_ontology,
                    relation=RelationType.EQUIVALENT if similarity > 0.9 else RelationType.RELATED,
                    confidence=confidence
                ))

        # Sort by confidence
        confidence_order = [
            MappingConfidence.EXACT,
            MappingConfidence.HIGH,
            MappingConfidence.MEDIUM,
            MappingConfidence.LOW,
            MappingConfidence.UNCERTAIN
        ]
        mappings.sort(key=lambda m: confidence_order.index(m.confidence))

        return MappingResult(
            source_field=field_name,
            source_value=field_value,
            mappings=mappings,
            best_match=mappings[0] if mappings else None,
            unmapped=len(mappings) == 0
        )

    def _normalize_value(self, value: str) -> str:
        """Normalize a value for matching"""
        # Remove common prefixes
        prefixes = ["ifc", "cobie", "type", "element"]
        normalized = value.lower().strip()

        for prefix in prefixes:
            if normalized.startswith(prefix):
                normalized = normalized[len(prefix):]

        return normalized.strip("_- ")

    def _matches(self, value: str, concept: str) -> bool:
        """Check if value matches concept"""
        normalized_value = self._normalize_value(value)
        normalized_concept = self._normalize_value(concept)
        return normalized_value == normalized_concept

    def _calculate_similarity(
        self,
        value: str,
        concept: OntologyConcept
    ) -> float:
        """Calculate similarity between value and concept"""
        value_lower = value.lower()
        concept_name_lower = concept.name.lower()
        concept_id_lower = concept.id.lower()

        # Exact match
        if value_lower == concept_name_lower or value_lower == concept_id_lower:
            return 1.0

        # Partial match in name
        if value_lower in concept_name_lower or concept_name_lower in value_lower:
            return 0.8

        # Check synonyms
        for key, synonyms in self.synonym_map.items():
            if key in value_lower:
                if key in concept_name_lower:
                    return 0.9
                for syn in synonyms:
                    if syn in concept_name_lower:
                        return 0.7

        # Definition match
        if concept.definition:
            if value_lower in concept.definition.lower():
                return 0.6

        return 0.0

    def _similarity_to_confidence(self, similarity: float) -> MappingConfidence:
        """Convert similarity score to confidence level"""
        if similarity >= 0.95:
            return MappingConfidence.EXACT
        elif similarity >= 0.8:
            return MappingConfidence.HIGH
        elif similarity >= 0.6:
            return MappingConfidence.MEDIUM
        elif similarity >= 0.4:
            return MappingConfidence.LOW
        else:
            return MappingConfidence.UNCERTAIN

    def map_schema(
        self,
        schema: Dict[str, List[str]],
        target_ontology: OntologyType = OntologyType.IFC
    ) -> OntologyMappingReport:
        """
        Map entire schema to target ontology.

        Args:
            schema: Dictionary of field names to sample values
            target_ontology: Target ontology

        Returns:
            Complete mapping report
        """
        all_mappings = []
        confidence_dist = {c.value: 0 for c in MappingConfidence}

        for field_name, sample_values in schema.items():
            # Use first sample value
            value = sample_values[0] if sample_values else field_name

            result = self.map_field(field_name, value, target_ontology=target_ontology)
            all_mappings.append(result)

            if result.best_match:
                confidence_dist[result.best_match.confidence.value] += 1

        mapped = sum(1 for m in all_mappings if not m.unmapped)
        unmapped = len(all_mappings) - mapped
        coverage = mapped / len(all_mappings) if all_mappings else 0

        recommendations = self._generate_recommendations(all_mappings, coverage)

        return OntologyMappingReport(
            total_fields=len(all_mappings),
            mapped_fields=mapped,
            unmapped_fields=unmapped,
            mappings=all_mappings,
            coverage=coverage,
            confidence_distribution=confidence_dist,
            recommendations=recommendations
        )

    def _generate_recommendations(
        self,
        mappings: List[MappingResult],
        coverage: float
    ) -> List[str]:
        """Generate recommendations for improving mappings"""
        recommendations = []

        if coverage < 0.7:
            recommendations.append(
                f"Low mapping coverage ({coverage:.0%}). Consider adding custom mappings."
            )

        low_confidence = [m for m in mappings
                         if m.best_match and m.best_match.confidence
                         in [MappingConfidence.LOW, MappingConfidence.UNCERTAIN]]
        if low_confidence:
            recommendations.append(
                f"{len(low_confidence)} mappings have low confidence. Review manually."
            )

        unmapped = [m for m in mappings if m.unmapped]
        if unmapped:
            fields = [m.source_field for m in unmapped[:5]]
            recommendations.append(
                f"Unmapped fields: {', '.join(fields)}. Add custom mappings."
            )

        return recommendations

    def create_mapping(
        self,
        source: str,
        source_ontology: OntologyType,
        target: str,
        target_ontology: OntologyType,
        relation: RelationType = RelationType.EQUIVALENT,
        notes: Optional[str] = None
    ) -> SemanticMapping:
        """Create a new manual mapping"""
        mapping = SemanticMapping(
            source_concept=source,
            source_ontology=source_ontology,
            target_concept=target,
            target_ontology=target_ontology,
            relation=relation,
            confidence=MappingConfidence.EXACT,
            notes=notes,
            created_by="manual"
        )
        self.mapping_rules.append(mapping)
        return mapping

    def export_mappings(self, format: str = "json") -> str:
        """Export all mappings"""
        if format == "json":
            mappings_data = []
            for rule in self.mapping_rules:
                mappings_data.append({
                    "source": rule.source_concept,
                    "source_ontology": rule.source_ontology.value,
                    "target": rule.target_concept,
                    "target_ontology": rule.target_ontology.value,
                    "relation": rule.relation.value,
                    "confidence": rule.confidence.value
                })
            return json.dumps(mappings_data, indent=2)
        else:
            raise ValueError(f"Unsupported format: {format}")

    def generate_report(self, report: OntologyMappingReport) -> str:
        """Generate mapping report"""
        output = f"""
# Ontology Mapping Report

## Summary
- **Total Fields:** {report.total_fields}
- **Mapped Fields:** {report.mapped_fields}
- **Unmapped Fields:** {report.unmapped_fields}
- **Coverage:** {report.coverage:.0%}

## Confidence Distribution
"""
        for conf, count in report.confidence_distribution.items():
            if count > 0:
                output += f"- **{conf.title()}:** {count}n"

        output += "n## Recommendationsn"
        for rec in report.recommendations:
            output += f"- {rec}n"

        output += "n## Mappingsn"
        for mapping in report.mappings[:20]:
            status = "✓" if not mapping.unmapped else "✗"
            target = mapping.best_match.target_concept if mapping.best_match else "unmapped"
            conf = mapping.best_match.confidence.value if mapping.best_match else "-"
            output += f"- {status} {mapping.source_field}: {mapping.source_value} → {target} ({conf})n"

        return output
```

## Common Use Cases

### Map Field to IFC

```python
mapper = OntologyMapper()

# Map a single field
result = mapper.map_field(
    field_name="element_type",
    field_value="Wall",
    target_ontology=OntologyType.IFC
)

if result.best_match:
    print(f"Mapped to: {result.best_match.target_concept}")
    print(f"Confidence: {result.best_match.confidence.value}")
```

### Map Entire Schema

```python
# Define schema with sample values
schema = {
    "element_type": ["Wall", "Door", "Window"],
    "level": ["Level 1", "Level 2"],
    "material": ["Concrete", "Steel"],
    "room_type": ["Office", "Corridor"]
}

report = mapper.map_schema(schema, target_ontology=OntologyType.IFC)

print(f"Coverage: {report.coverage:.0%}")
print(f"Mapped: {report.mapped_fields}/{report.total_fields}")
```

### Create Custom Mappings

```python
# Add custom mapping
mapper.create_mapping(
    source="CustomWallType",
    source_ontology=OntologyType.CUSTOM,
    target="IfcWall",
    target_ontology=OntologyType.IFC,
    relation=RelationType.EQUIVALENT,
    notes="Custom wall type from legacy system"
)
```

## Quick Reference

| Component | Purpose |
|-----------|---------|
| `OntologyMapper` | Main mapping engine |
| `OntologyType` | Standard ontologies (IFC, COBie, etc.) |
| `SemanticMapping` | Mapping between concepts |
| `MappingResult` | Result of mapping operation |
| `RelationType` | Relationship types |
| `MappingConfidence` | Confidence levels |

## Resources

- **Book**: "Data-Driven Construction" by Artem Boiko, Chapter 2.2
- **Website**: https://datadrivenconstruction.io

## Next Steps

- Use [open-data-integrator](../open-data-integrator/SKILL.md) for open data
- Use [data-model-designer](../../Chapter-2.5/data-model-designer/SKILL.md) for schema design
- Use [bim-validation-pipeline](../../Chapter-4.3/bim-validation-pipeline/SKILL.md) for validation