NavisworksTransport/doc/working/SmartTraversal_Lightweight_Preview_Implementation.md

8.2 KiB
Raw Blame History

轻量化智能遍历预览实施方案

目标

实现基于属性的智能遍历算法,替代现有的固定深度收集方式,专注于预览性能提升。保存逻辑暂时不修改。

核心修改点

1. 新增智能遍历算法SimplifiedModelSplitterManager.cs

PreviewSplitWithSmartTraversal方法

private List<SplitPreviewResult> PreviewSplitWithSmartTraversal(
    SplitConfiguration config, IGroupingStrategy strategy)
{
    var results = new List<SplitPreviewResult>();
    
    foreach (Model model in document.Models)
    {
        foreach (ModelItem rootChild in model.RootItem.Children)
        {
            TraverseAndRecord(rootChild, strategy, config, results, 1);
        }
    }
    
    return results;
}

TraverseAndRecord递归方法

private void TraverseAndRecord(ModelItem node, IGroupingStrategy strategy, 
    SplitConfiguration config, List<SplitPreviewResult> results, int currentDepth)
{
    // 检查当前节点的分层属性
    string layerValue = strategy.ExtractAttributeValue(node);
    
    if (!string.IsNullOrEmpty(layerValue))
    {
        // 找到分层属性,创建预览结果,停止该分支遍历
        var layerResult = CreateLightweightLayerResult(layerValue, node, strategy.GroupTypeName);
        results.Add(layerResult);
        return; // 关键:停止遍历该分支
    }
    
    // 未找到分层属性且未达深度限制,继续遍历子节点
    if (currentDepth < config.MaxDepth && node.Children != null)
    {
        foreach (ModelItem child in node.Children)
        {
            TraverseAndRecord(child, strategy, config, results, currentDepth + 1);
        }
    }
}

2. 最简化预览结果创建

CreateLightweightLayerResult方法

private SplitPreviewResult CreateLightweightLayerResult(string layerValue, ModelItem rootNode, string groupTypeName)
{
    return new SplitPreviewResult
    {
        LayerName = SanitizeLayerName(layerValue),
        Items = new ModelItemCollection { rootNode },
        Metadata = new Dictionary<string, object>
        {
            ["LayerValue"] = layerValue,
            ["RootNodeReference"] = rootNode,
            ["GroupType"] = groupTypeName
        }
    };
}

说明

  • 不设置 ItemCount、EstimatedFileSize、Status 等字段
  • 只包含预览必需的信息LayerName、根节点引用、元数据
  • 避免任何不必要的计算和统计

3. 策略接口扩展

IGroupingStrategy接口新增方法

public interface IGroupingStrategy
{
    string GroupTypeName { get; }
    
    // 现有方法保持不变
    Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config);
    
    // 新增:单节点属性检测
    string ExtractAttributeValue(ModelItem node);
}

4. 示例策略类升级

FloorAttributeStrategy新增实现

public string ExtractAttributeValue(ModelItem node)
{
    // 优先在"分层信息"类别中查找楼层属性
    return GetAttributeFromCategory(node, "分层信息", "楼层") ??
           GetAttributeFromCategory(node, "Identity Data", "Floor") ??
           GetAttributeFromCategory(node, "Constraints", "Level");
}

private string GetAttributeFromCategory(ModelItem node, string categoryName, string attributeName)
{
    try
    {
        foreach (PropertyCategory category in node.PropertyCategories)
        {
            if (category.DisplayName == categoryName)
            {
                foreach (DataProperty property in category.Properties)
                {
                    if (property.DisplayName == attributeName)
                    {
                        return property.Value.ToDisplayString();
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        LogManager.Warning($"获取属性失败: {ex.Message}");
    }
    
    return null;
}

5. 主入口方法修改

PreviewSplit方法调整

public List<SplitPreviewResult> PreviewSplit(SplitConfiguration config)
{
    try
    {
        // 缓存检查等现有逻辑保持不变...
        
        var strategy = CreateStrategy(config.Strategy);
        
        // 使用新的智能遍历完全替代GetItemsByDepthUnified
        LogManager.Info($"开始智能遍历分层预览,策略: {config.Strategy},深度限制: {config.MaxDepth}");
        var previewResults = PreviewSplitWithSmartTraversal(config, strategy);
        LogManager.Info($"智能遍历完成,识别到 {previewResults.Count} 个分层");
        
        // 缓存和状态更新等现有逻辑保持不变...
        
        return previewResults;
    }
    catch (Exception ex)
    {
        LogManager.Error($"智能遍历预览失败: {ex.Message}", ex);
        throw;
    }
}

性能优势

避免的性能瓶颈

  • 不再调用GetItemsByDepthUnified():避免收集所有深度内的节点
  • 不进行子节点收集:预览时只保存根节点引用
  • 不计算统计信息ItemCount、EstimatedFileSize、Status全部跳过
  • 智能分支停止:找到分层属性立即停止该分支遍历

预期性能提升

  • 内存占用大幅降低:从数万节点减少到只有分层根节点
  • 响应速度显著提升:预览结果近乎实时生成
  • CPU使用率降低:避免大量不必要的节点遍历和属性检查

算法逻辑对比

原有算法(性能瓶颈)

1. 收集所有指定深度内的节点GetItemsByDepthUnified
   └── 可能收集数万个节点到内存
2. 遍历所有节点检查属性GroupItems
   └── 对每个节点都进行属性查找
3. 统计每个分组的节点数量和文件大小
   └── 额外的计算开销

新算法(智能优化)

1. 从根节点开始递归遍历
   ├── 检查当前节点属性
   ├── 找到分层属性 → 停止该分支,记录结果
   └── 未找到 → 继续遍历子节点(受深度限制)
2. 只保存分层根节点引用
   └── 最小内存占用
3. 跳过所有统计计算
   └── 零额外开销

实施步骤

  1. 第一步在SimplifiedModelSplitterManager中实现智能遍历算法
  2. 第二步扩展IGroupingStrategy接口添加ExtractAttributeValue方法
  3. 第三步升级FloorAttributeStrategy实现ExtractAttributeValue
  4. 第四步修改PreviewSplit方法使用新算法
  5. 第五步:测试验证楼层分层的智能预览效果
  6. 第六步逐步升级其他策略类ZoneAttributeStrategy、SubSystemAttributeStrategy等

兼容性保证

  • 保留现有方法:所有原有方法和属性完全保持不变
  • 保存逻辑不变当前的ExecuteSplitAsync等保存方法完全不修改
  • 可回滚设计:如有问题可轻松恢复到原有实现

扩展性考虑

其他策略类升级

按照相同模式升级其他策略类:

  • ZoneAttributeStrategy: 在"分层信息"中查找"分区"属性
  • SubSystemAttributeStrategy: 在"分层信息"中查找"子系统"属性
  • FloorDetectionStrategy: 实现智能楼层检测逻辑

自定义属性支持

为用户自定义分层属性预留接口:

public class CustomAttributeStrategy : IGroupingStrategy
{
    private string _targetAttribute;
    private string _targetCategory;
    
    public string ExtractAttributeValue(ModelItem node)
    {
        return GetAttributeFromCategory(node, _targetCategory, _targetAttribute);
    }
}

测试验证计划

性能测试

  • 对比测试:新旧算法在相同模型上的性能表现
  • 内存监控:预览过程中的内存使用情况
  • 响应时间:从触发预览到显示结果的时间

功能测试

  • 分层准确性:确保智能遍历找到的分层与预期一致
  • 深度控制:验证遍历深度限制正常工作
  • 边界情况测试无分层属性、深度为0等特殊情况

预期收益

此方案专注于预览性能优化,预计将带来:

  • 90%以上的内存使用量减少
  • 80%以上的预览响应时间提升
  • 完全兼容现有功能,风险极低
  • 为后续智能检测功能奠定基础

通过这次重构,分层预览将从当前的性能瓶颈转变为系统的性能优势点。