Skip to content

Step 3: Query

Search, update, and maintain your knowledge abstract.


Goal

Query the knowledge abstract and implement maintenance workflows.


Query Interface

Search Functionality

def search(self, query: str, top_k: int = 5):
    """Search the knowledge abstract."""
    current_path = Path(self.config.kb_dir) / "current"

    ka = Template.create(self.config.template, self.config.language)
    ka.load(current_path)

    results = ka.search(query, top_k=top_k)
    return results

Q&A Functionality

def ask(self, question: str, top_k: int = 5):
    """Ask a question about the knowledge abstract."""
    current_path = Path(self.config.kb_dir) / "current"

    ka = Template.create(self.config.template, self.config.language)
    ka.load(current_path)

    response = ka.chat(question, top_k=top_k)
    return response.content

Interactive Query Shell

"""Step 3: Interactive Query Interface."""

import cmd
from kb_manager import KnowledgeBaseManager

class KBQueryShell(cmd.Cmd):
    intro = """
Knowledge Abstract Query Shell
==========================
Type 'help' for commands, 'quit' to exit

Commands:
  search <query>     - Semantic search
  ask <question>     - Ask a question
  stats              - Show KA statistics
  versions           - List versions
  backup             - Create backup
"""
    prompt = "ka> "

    def __init__(self):
        super().__init__()
        self.manager = KnowledgeBaseManager()
        self.ka = None
        self._load_kb()

    def _load_kb(self):
        """Load current knowledge abstract."""
        current_path = Path(self.manager.config.kb_dir) / "current"
        if current_path.exists():
            self.ka = Template.create(
                self.manager.config.template,
                self.manager.config.language
            )
            self.ka.load(current_path)
            print(f"Loaded: {self.manager.config.name}")
        else:
            print("Warning: No knowledge abstract found")

    def do_search(self, arg):
        """Search the knowledge abstract: search <query>"""
        if not arg:
            print("Usage: search <query>")
            return

        if not self.ka:
            print("No knowledge abstract loaded")
            return

        nodes, edges = self.ka.search(arg, top_k=5)

        print(f"\nFound {len(nodes)} nodes and {len(edges)} edges:\n")
        for i, node in enumerate(nodes, 1):
            print(f"{i}. [Node] {node.name} ({node.type})")
        for i, edge in enumerate(edges, len(nodes) + 1):
            print(f"{i}. [Edge] {edge.source} -> {edge.target}")
        print()

    def do_ask(self, arg):
        """Ask a question: ask <question>"""
        if not arg:
            print("Usage: ask <question>")
            return

        if not self.ka:
            print("No knowledge abstract loaded")
            return

        print("\nThinking...")
        answer = self.ka.chat(arg).content
        print(f"\n{answer}\n")

    def do_stats(self, arg):
        """Show knowledge abstract statistics."""
        if not self.ka:
            print("No knowledge abstract loaded")
            return

        print("\nKnowledge Abstract Statistics:")
        print(f"  Nodes: {len(self.ka.nodes)}")
        print(f"  Edges: {len(self.ka.edges)}")
        print(f"  Template: {self.manager.config.template}")

        # Node types
        from collections import Counter
        types = Counter(n.type for n in self.ka.nodes)
        print("\nNode Types:")
        for t, count in types.most_common():
            print(f"  {t}: {count}")
        print()

    def do_versions(self, arg):
        """List all versions."""
        kb_dir = Path(self.manager.config.kb_dir)
        versions = [d.name for d in kb_dir.iterdir() if d.is_dir()]

        print("\nVersions:")
        for v in sorted(versions):
            marker = " (current)" if v == "current" else ""
            print(f"  {v}{marker}")
        print()

    def do_backup(self, arg):
        """Create backup of current version."""
        import shutil

        current = Path(self.manager.config.kb_dir) / "current"
        if not current.exists():
            print("No current version to backup")
            return

        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_path = Path(self.manager.config.backup_dir) / f"backup_{timestamp}"

        shutil.copytree(current, backup_path)
        print(f"✓ Backup created: {backup_path}\n")

    def do_quit(self, arg):
        """Exit the shell."""
        print("Goodbye!")
        return True

    do_exit = do_quit

if __name__ == "__main__":
    KBQueryShell().cmdloop()

Maintenance Operations

Backup Strategy

def create_backup(self, name: Optional[str] = None):
    """Create a backup of current knowledge abstract."""
    import shutil

    current = Path(self.config.kb_dir) / "current"
    if not current.exists():
        raise ValueError("No current version to backup")

    if name is None:
        name = datetime.now().strftime("backup_%Y%m%d_%H%M%S")

    backup_path = Path(self.config.backup_dir) / name
    shutil.copytree(current, backup_path)

    print(f"✓ Backup created: {backup_path}")
    return backup_path

def restore_backup(self, backup_name: str):
    """Restore from backup."""
    import shutil

    backup_path = Path(self.config.backup_dir) / backup_name
    if not backup_path.exists():
        raise ValueError(f"Backup not found: {backup_name}")

    # Save current as version first
    current = Path(self.config.kb_dir) / "current"
    if current.exists():
        self._save_current_as_version("pre-restore")

    # Restore backup
    if current.exists():
        shutil.rmtree(current)
    shutil.copytree(backup_path, current)

    print(f"✓ Restored from: {backup_path}")

Version Management

def list_versions(self):
    """List all versions."""
    kb_dir = Path(self.config.kb_dir)
    versions = []

    for item in kb_dir.iterdir():
        if item.is_dir() and item.name != "current":
            # Get version info
            metadata_file = item / "metadata.json"
            if metadata_file.exists():
                import json
                with open(metadata_file) as f:
                    metadata = json.load(f)
                versions.append({
                    "name": item.name,
                    "created": metadata.get("created_at", "unknown"),
                    "updated": metadata.get("updated_at", "unknown")
                })

    return sorted(versions, key=lambda x: x["name"])

def rollback(self, version: str):
    """Rollback to a specific version."""
    version_path = Path(self.config.kb_dir) / version
    if not version_path.exists():
        raise ValueError(f"Version not found: {version}")

    # Update current symlink
    current_link = Path(self.config.kb_dir) / "current"
    if current_link.exists():
        current_link.unlink()
    current_link.symlink_to(version_path, target_is_directory=True)

    print(f"✓ Rolled back to: {version}")

Cleanup

def cleanup_old_versions(self, keep: int = 10):
    """Remove old versions, keeping only the most recent."""
    versions = self.list_versions()

    if len(versions) <= keep:
        print(f"No cleanup needed ({len(versions)} versions)")
        return

    to_remove = versions[:-keep]
    for v in to_remove:
        version_path = Path(self.config.kb_dir) / v["name"]
        shutil.rmtree(version_path)
        print(f"Removed: {v['name']}")

    print(f"✓ Cleaned up {len(to_remove)} old versions")

Export and Reporting

Export to JSON

def export_to_json(self, output_file: str = "kb_export.json"):
    """Export knowledge abstract to JSON."""
    data = {
        "config": {
            "name": self.config.name,
            "template": self.config.template,
            "language": self.config.language
        },
        "data": self.ka.data.model_dump(),
        "metadata": self.ka.metadata
    }

    with open(output_file, "w") as f:
        json.dump(data, f, indent=2, default=str)

    print(f"✓ Exported to: {output_file}")

Generate Report

def generate_report(self):
    """Generate knowledge abstract report."""
    from collections import Counter

    report = []
    report.append("# Knowledge Abstract Report")
    report.append(f"\nName: {self.config.name}")
    report.append(f"Template: {self.config.template}")
    report.append(f"\nStatistics:")
    report.append(f"- Entities: {len(self.ka.data.entities)}")
    report.append(f"- Relations: {len(self.ka.data.relations)}")

    # Entity types
    types = Counter(e.type for e in self.ka.data.entities)
    report.append("\n## Entity Types")
    for t, count in types.most_common():
        report.append(f"- {t}: {count}")

    return "\n".join(report)

Summary

You now have a complete knowledge abstract system with:

✓ Document ingestion with versioning
✓ Search and Q&A capabilities
✓ Backup and restore functionality
✓ Maintenance operations
✓ Export and reporting

Next Steps

  • Schedule regular backups
  • Monitor knowledge abstract growth
  • Set up automated ingestion pipelines
  • Integrate with your applications

See Also