427 lines
15 KiB
Markdown
Raw Permalink Normal View History

2026-01-06 22:59:58 +08:00
# Design Document: Infrared Camera Data Query Enhancement
## Overview
This design enhances the `FindDatas` method in `MeasuresTemperatureResultAppService` to query temperature measurement data from infrared cameras stored in the `OriginalInspectionStoreResult` MongoDB collection. The enhancement introduces intelligent camera identification, fuzzy equipment name matching with 85% similarity threshold, and structured parsing of temperature data from result strings.
The design maintains backward compatibility with existing thermal imaging device queries while adding support for infrared camera data sources.
## Architecture
### High-Level Flow
```
FindDatas Request
[1] Apply Infrared Camera Filter (CamName contains "热成像" OR ends with 'B')
[2] Query OriginalInspectionStoreResult with time/filters
[3] For each result:
├─ Apply Equipment Fuzzy Matching (85% similarity)
├─ Parse Temperature Data from Result field
└─ Create MeasureTemperatureResultOutput records
[4] Apply Name Filter (if specified)
[5] Sort, Paginate, Return Results
```
### Integration Points
- **Existing Method**: `FindMeasureTempertureResults` - Currently handles thermal imaging devices (DevType 12, 22)
- **New Data Source**: `OriginalInspectionStoreResult` collection - Contains infrared camera inspection data
- **Shared Output**: `MeasureTemperatureResultOutput` - Common DTO for all temperature results
## Components and Interfaces
### Modified Method Signature
```csharp
[HttpPost, Description("查询温度测量结果")]
[Abp.Domain.Uow.UnitOfWork(true)]
[AbpAllowAnonymous]
[ShowApi]
public RequestPageResult<MeasureTemperatureResultOutput> FindDatas(
PageSearchCondition<MeasureTemperatureResultSearchConditonInput> searchCondition)
```
### New Helper Methods
#### 1. IsInfraredCamera
```csharp
/// <summary>
/// Determines if a camera name indicates an infrared camera
/// </summary>
/// <param name="camName">Camera name from OriginalInspectionStoreResult</param>
/// <returns>True if camera is infrared type</returns>
private bool IsInfraredCamera(string camName)
```
**Logic:**
- Returns `true` if `camName` contains "热成像"
- Returns `true` if `camName` ends with 'B'
- Returns `false` otherwise
- Handles null/empty strings safely
#### 2. CalculateSimilarity (Enhanced)
```csharp
/// <summary>
/// Calculates string similarity using Levenshtein distance algorithm
/// </summary>
/// <param name="source">Source string</param>
/// <param name="target">Target string</param>
/// <returns>Similarity score between 0.0 and 1.0</returns>
private double CalculateSimilarity(string source, string target)
```
**Current Implementation Issue:**
The existing implementation uses simple character matching which is not accurate for 85% similarity requirements.
**Enhanced Logic:**
- Use Levenshtein distance algorithm for accurate similarity calculation
- Formula: `similarity = 1.0 - (levenshteinDistance / maxLength)`
- Handle null/empty strings by returning 0.0
- Case-insensitive comparison
#### 3. ParseTemperatureFromInfraredResult
```csharp
/// <summary>
/// Parses temperature data from infrared camera result string
/// </summary>
/// <param name="data">Original inspection store result</param>
/// <param name="equipmentInfo">Associated equipment (may be null)</param>
/// <returns>List of temperature measurement outputs</returns>
private List<MeasureTemperatureResultOutput> ParseTemperatureFromInfraredResult(
OriginalInspectionStoreResult data,
EquipmentInfo equipmentInfo)
```
**Logic:**
- Split `Result` field by delimiters: `,`, ``, `\r\n`, `\n`
- For each segment:
- Check if contains `:` or ``
- If yes: split into name and value parts
- Extract numeric temperature using regex: `@"-?\d+(?:\.\d+)?"`
- Create `MeasureTemperatureResultOutput` with parsed data
- Handle missing/invalid data gracefully
- Log parsing failures with original Result string
#### 4. MatchesEquipmentByName
```csharp
/// <summary>
/// Checks if inspection data matches equipment using fuzzy name matching
/// </summary>
/// <param name="data">Original inspection store result</param>
/// <param name="equipment">Equipment to match against</param>
/// <param name="threshold">Similarity threshold (default 0.85)</param>
/// <returns>True if names match with sufficient similarity</returns>
private bool MatchesEquipmentByName(
OriginalInspectionStoreResult data,
EquipmentInfo equipment,
double threshold = 0.85)
```
**Logic:**
- Check `data.EquipmentInfoName` against `equipment.Name`
- Check `data.Name` against `equipment.Name`
- Return `true` if either similarity >= threshold
- Return `false` if both similarities < threshold
## Data Models
### Input: MeasureTemperatureResultSearchConditonInput
```csharp
public class MeasureTemperatureResultSearchConditonInput
{
public Guid? EquipmentInfoId { get; set; }
public string Name { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
// ... other existing properties
}
```
### Source: OriginalInspectionStoreResult
```csharp
public class OriginalInspectionStoreResult
{
public string CamName { get; set; } // Camera identifier
public string PresetCode { get; set; } // Preset position code
public string Result { get; set; } // Temperature data string
public DateTime Time { get; set; } // Measurement time
public string CaptureTime { get; set; } // Capture timestamp
public string Status { get; set; } // Status code
public string Message { get; set; } // Result message
public string Name { get; set; } // Item name
public string EquipmentInfoName { get; set; } // Equipment name
public Guid? EquipmentInfoId { get; set; } // Equipment ID
// ... other properties
}
```
### Output: MeasureTemperatureResultOutput
```csharp
public class MeasureTemperatureResultOutput
{
public Guid Id { get; set; }
public Guid MeasureTemperaturePointId { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public float? TemperatureValue { get; set; }
public string Message { get; set; }
public DateTime? MeasureTime { get; set; }
public int Status { get; set; }
public Guid? EquipmentInfoId { get; set; }
public string EquipmentInfoName { get; set; }
// ... other properties
}
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property 1: Infrared Camera Identification Completeness
*For any* OriginalInspectionStoreResult record where CamName contains "热成像" or ends with 'B', the IsInfraredCamera method should return true.
**Validates: Requirements 1.1, 1.2, 1.3**
### Property 2: Similarity Calculation Symmetry
*For any* two non-empty strings A and B, CalculateSimilarity(A, B) should equal CalculateSimilarity(B, A).
**Validates: Requirements 2.4**
### Property 3: Similarity Score Bounds
*For any* two strings A and B, CalculateSimilarity(A, B) should return a value between 0.0 and 1.0 inclusive.
**Validates: Requirements 2.4**
### Property 4: Equipment Matching Threshold
*For any* OriginalInspectionStoreResult and Equipment pair, if either EquipmentInfoName or Name has similarity >= 0.85 with Equipment.Name, then MatchesEquipmentByName should return true.
**Validates: Requirements 2.5, 2.6**
### Property 5: Valid Temperature Data Parsing
*For any* Result string containing segments in format "name:value" where value is numeric, ParseTemperatureFromInfraredResult should extract at least one MeasureTemperatureResultOutput with non-null TemperatureValue.
**Validates: Requirements 3.1, 3.2, 3.3, 3.5, 3.6**
### Property 6: Invalid Segment Skipping
*For any* Result string containing segments without colons, ParseTemperatureFromInfraredResult should skip those segments and continue processing remaining segments.
**Validates: Requirements 3.4, 3.7**
### Property 7: Filter Application Order
*For any* query with time range, equipment filter, and name filter, the System should apply filters in order: infrared camera → time range → equipment matching → temperature parsing → name filtering.
**Validates: Requirements 4.1, 4.2, 4.3, 4.4, 4.5**
### Property 8: Null Safety in Similarity Calculation
*For any* call to CalculateSimilarity where either parameter is null or empty, the method should return 0.0 without throwing exceptions.
**Validates: Requirements 5.2**
### Property 9: Parsing Error Isolation
*For any* OriginalInspectionStoreResult with invalid Result format, parsing failures should not prevent processing of other records in the result set.
**Validates: Requirements 5.1, 5.5**
## Error Handling
### Exception Scenarios
1. **MongoDB Query Failures**
- Catch: `MongoException`, `TimeoutException`
- Action: Log error with query details, return error response
- User Message: "数据库查询失败,请稍后重试"
2. **Temperature Parsing Failures**
- Catch: `FormatException`, `RegexMatchTimeoutException`
- Action: Log warning with Result string, skip record, continue
- No user-facing error (graceful degradation)
3. **Similarity Calculation Errors**
- Catch: `ArgumentException`, `NullReferenceException`
- Action: Return 0.0 similarity, log warning
- Continue processing
4. **Equipment Lookup Failures**
- Catch: `InvalidOperationException`
- Action: Log warning, skip equipment matching for that record
- Continue with other records
### Logging Strategy
```csharp
// Error level - Critical failures
Log4Helper.Error(this.GetType(), "查询红外测温数据失败", ex);
// Warning level - Recoverable issues
Log4Helper.Warn(this.GetType(), $"解析温度数据失败: {data.Result}", ex);
// Info level - Normal operations
Log4Helper.Info(this.GetType(), $"查询到 {count} 条红外测温数据");
```
## Testing Strategy
### Unit Tests
Unit tests will verify specific examples and edge cases:
1. **IsInfraredCamera Tests**
- Test camera name containing "热成像"
- Test camera name ending with 'B'
- Test camera name with both conditions
- Test camera name with neither condition
- Test null/empty camera names
2. **CalculateSimilarity Tests**
- Test identical strings (should return 1.0)
- Test completely different strings (should return close to 0.0)
- Test strings with 85% similarity
- Test null and empty string handling
- Test case sensitivity
3. **ParseTemperatureFromInfraredResult Tests**
- Test valid format: "2BL_C相连接点-12.5℃"
- Test multiple temperature points separated by commas
- Test mixed valid and invalid segments
- Test empty Result string
- Test Result with no colons
- Test negative temperatures
- Test decimal temperatures
4. **MatchesEquipmentByName Tests**
- Test exact name match
- Test 85% similarity match
- Test 84% similarity (should not match)
- Test null equipment names
- Test matching via EquipmentInfoName
- Test matching via Name field
### Property-Based Tests
Property-based tests will verify universal properties across randomized inputs. Each test will run a minimum of 100 iterations.
1. **Property Test: Similarity Symmetry**
- **Property 2: Similarity Calculation Symmetry**
- **Validates: Requirements 2.4**
- Generate random string pairs
- Verify CalculateSimilarity(A, B) == CalculateSimilarity(B, A)
2. **Property Test: Similarity Bounds**
- **Property 3: Similarity Score Bounds**
- **Validates: Requirements 2.4**
- Generate random string pairs
- Verify 0.0 <= CalculateSimilarity(A, B) <= 1.0
3. **Property Test: Infrared Camera Identification**
- **Property 1: Infrared Camera Identification Completeness**
- **Validates: Requirements 1.1, 1.2, 1.3**
- Generate camera names with "热成像" or ending with 'B'
- Verify IsInfraredCamera returns true for all
4. **Property Test: Temperature Parsing Completeness**
- **Property 5: Valid Temperature Data Parsing**
- **Validates: Requirements 3.1, 3.2, 3.3, 3.5, 3.6**
- Generate Result strings with valid "name:value" format
- Verify at least one temperature point is extracted
5. **Property Test: Invalid Segment Handling**
- **Property 6: Invalid Segment Skipping**
- **Validates: Requirements 3.4, 3.7**
- Generate Result strings with mix of valid and invalid segments
- Verify invalid segments are skipped without errors
### Integration Tests
Integration tests will verify end-to-end functionality:
1. **Full Query Flow Test**
- Insert test data into OriginalInspectionStoreResult
- Call FindDatas with various filters
- Verify correct results returned
- Verify pagination works correctly
2. **Equipment Matching Integration Test**
- Create equipment with specific name
- Insert inspection data with similar names
- Verify fuzzy matching works at 85% threshold
3. **Multi-Source Query Test**
- Verify thermal imaging and infrared camera data can coexist
- Verify both data sources are queried correctly
### Test Framework
- **Unit Testing**: xUnit or NUnit
- **Property-Based Testing**: FsCheck (for C#)
- **Mocking**: Moq for repository mocking
- **Test Data**: Builder pattern for creating test entities
### Test Configuration
```csharp
[Property(MaxTest = 100)]
public Property SimilarityIsSymmetric()
{
return Prop.ForAll<string, string>((a, b) =>
{
var sim1 = CalculateSimilarity(a, b);
var sim2 = CalculateSimilarity(b, a);
return Math.Abs(sim1 - sim2) < 0.0001;
});
}
```
## Implementation Notes
### Performance Considerations
1. **Levenshtein Distance Optimization**
- Use iterative algorithm with O(n*m) complexity
- Consider caching for repeated comparisons
- Early exit if strings differ significantly in length
2. **MongoDB Query Optimization**
- Add index on `CamName` field for faster filtering
- Add index on `Time` field for time range queries
- Use projection to retrieve only needed fields
3. **Batch Processing**
- Process temperature parsing in parallel if result set is large
- Consider streaming results for very large datasets
### Backward Compatibility
- Existing `FindMeasureTempertureResults` logic remains unchanged
- New infrared camera logic is additive
- Both thermal imaging and infrared data sources work independently
- Shared output DTO ensures consistent API response
### Configuration
Consider adding configuration for:
- Similarity threshold (default 0.85, configurable)
- Infrared camera name patterns (extensible list)
- Temperature parsing regex patterns
- Logging verbosity levels