Files
oneapp_docs/service_component/GlobalSearch.md
2025-09-24 14:08:54 +08:00

610 lines
17 KiB
Markdown

# GlobalSearch - 全局搜索模块
## 模块概述
`GlobalSearch` 是 OneApp 的全局搜索模块,提供了跨模块的统一搜索功能。该模块支持多种内容类型的搜索,包括智能搜索建议、搜索历史管理、搜索结果优化等功能,为用户提供高效、精准的搜索体验。
## 核心功能
### 1. 跨模块内容搜索
- **统一搜索入口**:提供全局统一的搜索接口
- **多模块索引**:聚合各模块的可搜索内容
- **内容分类**:按类型分类搜索结果
- **权限控制**:基于用户权限过滤搜索结果
### 2. 智能搜索建议
- **实时建议**:输入时实时提供搜索建议
- **热门搜索**:展示热门搜索关键词
- **个性化推荐**:基于用户行为的个性化建议
- **拼写纠错**:智能纠正搜索词拼写错误
### 3. 搜索历史管理
- **历史记录**:保存用户搜索历史
- **快速访问**:快速访问历史搜索结果
- **清理管理**:支持清理搜索历史
- **隐私保护**:敏感搜索历史加密存储
### 4. 搜索结果优化
- **相关性排序**:按相关性智能排序
- **结果聚合**:相似结果智能聚合
- **高亮显示**:关键词高亮显示
- **分页加载**:大量结果分页展示
## 技术架构
### 架构设计
```
┌─────────────────────────────────────┐
│ 搜索界面层 │
│ (Search UI Components) │
├─────────────────────────────────────┤
│ GlobalSearch 模块 │
│ ┌──────────┬──────────┬──────────┐ │
│ │ 搜索引擎 │ 索引管理 │ 结果处理 │ │
│ ├──────────┼──────────┼──────────┤ │
│ │ 建议系统 │ 历史管理 │ 缓存层 │ │
│ └──────────┴──────────┴──────────┘ │
├─────────────────────────────────────┤
│ 模块搜索接口 │
│ ┌──────────┬──────────┬──────────┐ │
│ │ 车辆模块 │ 订单模块 │ 设置模块 │ │
│ └──────────┴──────────┴──────────┘ │
├─────────────────────────────────────┤
│ 数据存储层 │
│ (Local DB + Remote Index) │
└─────────────────────────────────────┘
```
### 核心组件
#### 1. 通用搜索组件 (GlobalSearchCommonWidget)
基于真实项目代码的通用搜索组件:
```dart
/// 全局搜索通用组件
class GlobalSearchCommonWidget extends StatefulWidget {
const GlobalSearchCommonWidget({
Key? key,
required this.selectCommonSearchItem
}) : super(key: key);
final SelectCommonSearch selectCommonSearchItem;
@override
State<GlobalSearchCommonWidget> createState() =>
_GlobalSearchCommonWidgetState();
}
/// 搜索项目数据模型
class SearchItemBean {
String name;
String event;
SearchItemBean({required this.name, required this.event});
}
/// 选择通用搜索项回调
typedef SelectCommonSearch = void Function(SearchItemBean commonSearchItem);
```
#### 2. 搜索组件实现
```dart
class _GlobalSearchCommonWidgetState extends State<GlobalSearchCommonWidget> {
List<SearchItemBean> commonSearchBeanList = [];
String tips = '';
@override
Widget build(BuildContext context) {
if (commonSearchBeanList.isEmpty) {
return Container();
}
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.fromLTRB(15, 15, 12, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
tips,
style: OneTextStyle.content(color: OneColors.tc),
),
],
),
SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 12,
children: _buildHistoryTag(commonSearchBeanList),
),
],
),
),
],
);
}
/// 构建历史搜索标签
List<Widget> _buildHistoryTag(List<SearchItemBean> historys) {
List<Widget> historyWidgets = [];
for (int i = 0; i < historys.length; i++) {
var displayName = historys[i].name;
if (displayName.length > 8) {
displayName = displayName.substring(0, 8) + '...';
}
historyWidgets.add(InkWell(
onTap: () {
widget.selectCommonSearchItem(historys[i]);
},
child: Container(
padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
decoration: BoxDecoration(
color: OneColors.bgcSub1,
borderRadius: BorderRadius.all(Radius.circular(2)),
),
child: Text(
displayName,
style: OneTextStyle.content(
color: OneColors.tc.withOpacity(0.55),
),
),
),
));
}
return historyWidgets;
}
@override
void initState() {
super.initState();
getCommonSearchResult();
}
/// 获取通用搜索结果
void getCommonSearchResult() {
// 实际项目中的搜索数据获取逻辑
}
}
```
#### 3. 搜索组件架构
实际项目包含的搜索组件:
- **QuicklyAccess.dart**: 快速访问组件
- **search_all_result_widget.dart**: 全部搜索结果组件
- **search_common_widget.dart**: 通用搜索组件
- **search_event_result_widget.dart**: 事件搜索结果组件
- **search_history_widget.dart**: 搜索历史组件
- **search_input_TextField_widget.dart**: 搜索输入框组件
- **search_mall_result_widget.dart**: 商城搜索结果组件
- **search_post_result_widget.dart**: 帖子搜索结果组件
- **search_result_widget.dart**: 搜索结果组件
## 数据模型
### 搜索查询模型
```dart
class SearchQuery {
final String keyword;
final List<String> categories;
final SearchScope scope;
final SortOption sortBy;
final int page;
final int pageSize;
final Map<String, dynamic> filters;
final bool includeHistory;
}
enum SearchScope {
all, // 全部内容
vehicle, // 车辆相关
order, // 订单相关
service, // 服务相关
settings, // 设置相关
help // 帮助文档
}
enum SortOption {
relevance, // 相关性
time, // 时间
popularity, // 热度
alphabetical // 字母顺序
}
```
### 搜索结果模型
```dart
class SearchResult {
final String query;
final int totalCount;
final List<SearchResultItem> items;
final List<SearchSuggestion> suggestions;
final Duration searchTime;
final Map<String, int> categoryCount;
final bool hasMore;
}
class SearchResultItem {
final String id;
final String title;
final String? subtitle;
final String? description;
final String category;
final String moduleId;
final String? imageUrl;
final double relevanceScore;
final DateTime? timestamp;
final Map<String, dynamic> metadata;
final List<HighlightRange> highlights;
}
```
### 搜索建议模型
```dart
class SearchSuggestion {
final String text;
final SuggestionType type;
final String? category;
final int frequency;
final double relevance;
final Map<String, dynamic>? metadata;
}
enum SuggestionType {
keyword, // 关键词建议
history, // 历史搜索
popular, // 热门搜索
completion, // 自动补全
correction // 拼写纠错
}
```
## API 接口
### 搜索接口
```dart
abstract class GlobalSearchService {
// 执行全局搜索
Future<ApiResponse<SearchResult>> search(SearchRequest request);
// 获取搜索建议
Future<ApiResponse<List<SearchSuggestion>>> getSuggestions(SuggestionRequest request);
// 获取热门搜索
Future<ApiResponse<List<String>>> getPopularSearches();
// 获取搜索历史
Future<ApiResponse<List<SearchRecord>>> getSearchHistory(HistoryRequest request);
}
```
### 索引管理接口
```dart
abstract class SearchIndexService {
// 更新搜索索引
Future<ApiResponse<bool>> updateSearchIndex(UpdateIndexRequest request);
// 删除搜索索引
Future<ApiResponse<bool>> deleteSearchIndex(DeleteIndexRequest request);
// 获取索引状态
Future<ApiResponse<IndexStatus>> getIndexStatus(String moduleId);
}
```
### 搜索提供者接口
```dart
abstract class SearchProvider {
// 搜索提供者ID
String get providerId;
// 支持的搜索类别
List<String> get supportedCategories;
// 执行搜索
Future<List<SearchResultItem>> search(SearchQuery query);
// 获取可搜索项目
Future<List<SearchableItem>> getSearchableItems();
// 获取搜索建议
Future<List<SearchSuggestion>> getSuggestions(String input);
}
```
## 配置管理
### 搜索配置
```dart
class GlobalSearchConfig {
final int maxResults;
final int suggestionLimit;
final bool enableHistory;
final bool enableSuggestions;
final Duration cacheExpiry;
final List<String> enabledModules;
final Map<String, double> categoryWeights;
static const GlobalSearchConfig defaultConfig = GlobalSearchConfig(
maxResults: 100,
suggestionLimit: 10,
enableHistory: true,
enableSuggestions: true,
cacheExpiry: Duration(minutes: 30),
enabledModules: ['vehicle', 'order', 'service', 'settings'],
categoryWeights: {
'vehicle': 1.0,
'order': 0.8,
'service': 0.9,
'settings': 0.6,
},
);
}
```
### 索引配置
```dart
class SearchIndexConfig {
final bool enableRealTimeIndex;
final Duration indexUpdateInterval;
final int maxIndexSize;
final List<String> indexedFields;
final Map<String, int> fieldWeights;
static const SearchIndexConfig defaultIndexConfig = SearchIndexConfig(
enableRealTimeIndex: true,
indexUpdateInterval: Duration(minutes: 5),
maxIndexSize: 10000,
indexedFields: ['title', 'description', 'tags', 'content'],
fieldWeights: {
'title': 3,
'description': 2,
'tags': 2,
'content': 1,
},
);
}
```
## 使用示例
### 基本搜索功能
```dart
// 初始化全局搜索
final globalSearch = GlobalSearchEngine.instance;
await globalSearch.initialize(GlobalSearchConfig.defaultConfig);
// 执行搜索
final searchQuery = SearchQuery(
keyword: '充电',
categories: ['vehicle', 'service'],
scope: SearchScope.all,
sortBy: SortOption.relevance,
page: 1,
pageSize: 20,
);
final searchResult = await globalSearch.search(searchQuery);
// 处理搜索结果
for (final item in searchResult.items) {
print('${item.title}: ${item.description}');
print('类别: ${item.category}, 相关性: ${item.relevanceScore}');
}
```
### 搜索建议功能
```dart
// 获取输入建议
final suggestions = await globalSearch.getSuggestions('充电');
// 显示建议列表
for (final suggestion in suggestions) {
switch (suggestion.type) {
case SuggestionType.completion:
print('补全: ${suggestion.text}');
break;
case SuggestionType.history:
print('历史: ${suggestion.text}');
break;
case SuggestionType.popular:
print('热门: ${suggestion.text}');
break;
}
}
// 获取热门搜索
final popularSearches = await globalSearch.getPopularSearches();
print('热门搜索: ${popularSearches.join(', ')}');
```
### 搜索历史管理
```dart
// 添加搜索记录
final searchRecord = SearchRecord(
query: '充电站',
timestamp: DateTime.now(),
resultCount: 25,
category: 'vehicle',
);
await SearchHistoryManager.instance.addSearchRecord(searchRecord);
// 获取搜索历史
final history = await SearchHistoryManager.instance.getSearchHistory(limit: 10);
for (final record in history) {
print('${record.query} - ${record.timestamp}');
}
// 清空搜索历史
await SearchHistoryManager.instance.clearSearchHistory();
```
### 注册搜索提供者
```dart
// 实现搜索提供者
class VehicleSearchProvider extends SearchProvider {
@override
String get providerId => 'vehicle_search';
@override
List<String> get supportedCategories => ['vehicle', 'charging', 'maintenance'];
@override
Future<List<SearchResultItem>> search(SearchQuery query) async {
// 实现车辆相关内容搜索
final vehicles = await vehicleService.searchVehicles(query.keyword);
return vehicles.map((vehicle) => SearchResultItem(
id: vehicle.id,
title: vehicle.name,
description: vehicle.description,
category: 'vehicle',
moduleId: 'app_car',
relevanceScore: calculateRelevance(query.keyword, vehicle),
)).toList();
}
@override
Future<List<SearchSuggestion>> getSuggestions(String input) async {
// 返回车辆相关搜索建议
return vehicleService.getSearchSuggestions(input);
}
}
// 注册搜索提供者
globalSearch.registerSearchProvider(VehicleSearchProvider());
```
## 测试策略
### 单元测试
```dart
group('GlobalSearch Tests', () {
test('should return search results', () async {
// Given
final searchEngine = GlobalSearchEngine();
final query = SearchQuery(keyword: 'test', scope: SearchScope.all);
// When
final result = await searchEngine.search(query);
// Then
expect(result.items, isNotEmpty);
expect(result.query, 'test');
});
test('should provide search suggestions', () async {
// Given
final suggestionSystem = SearchSuggestionSystem();
// When
final suggestions = await suggestionSystem.generateSuggestions('cha');
// Then
expect(suggestions, isNotEmpty);
expect(suggestions.first.text, contains('cha'));
});
});
```
### 集成测试
```dart
group('Search Integration Tests', () {
testWidgets('complete search flow', (tester) async {
// 1. 输入搜索关键词
await tester.enterText(find.byKey(Key('search_input')), '充电');
// 2. 验证搜索建议显示
expect(find.text('充电站'), findsOneWidget);
expect(find.text('充电桩'), findsOneWidget);
// 3. 执行搜索
await tester.tap(find.byKey(Key('search_button')));
await tester.pumpAndSettle();
// 4. 验证搜索结果
expect(find.byType(SearchResultItem), findsWidgets);
});
});
```
## 性能优化
### 搜索性能优化
- **索引优化**:使用倒排索引提高搜索速度
- **缓存策略**:热门搜索结果缓存
- **分页加载**:大结果集分页加载
- **异步处理**:搜索操作异步处理
### 内存优化
- **结果限制**:限制搜索结果数量
- **懒加载**:搜索结果懒加载
- **对象池**:复用搜索对象
- **内存回收**:及时回收不用的搜索数据
## 算法和策略
### 相关性算法
```dart
class RelevanceCalculator {
// 计算文本相关性
double calculateTextRelevance(String query, String text);
// 计算标题权重
double calculateTitleWeight(String query, String title);
// 计算类别权重
double calculateCategoryWeight(String category);
// 计算综合得分
double calculateFinalScore(Map<String, double> scores);
}
```
### 搜索优化策略
- **查询扩展**:同义词和相关词扩展
- **模糊匹配**:支持模糊匹配搜索
- **权重调整**:动态调整搜索权重
- **个性化排序**:基于用户行为的个性化排序
## 版本历史
### v0.3.2+5 (当前版本)
- 新增语义搜索功能
- 优化搜索性能和准确性
- 支持多语言搜索
- 修复搜索结果排序问题
### v0.3.1
- 支持实时搜索建议
- 新增搜索历史管理
- 优化搜索索引结构
- 改进搜索结果展示
## 依赖关系
### 内部依赖
- `basic_storage`: 本地数据存储
- `basic_network`: 网络请求服务
- `basic_utils`: 工具类库
- `basic_logger`: 日志记录
### 外部依赖
- `sqflite`: 本地数据库
- `fuzzywuzzy`: 模糊匹配算法
- `rxdart`: 响应式编程
- `collection`: 集合工具
## 总结
`GlobalSearch` 模块为 OneApp 提供了强大的全局搜索能力,通过统一的搜索接口、智能的搜索建议、完善的历史管理和优化的搜索结果,为用户提供了高效、精准的搜索体验。该模块的设计充分考虑了可扩展性、性能优化和用户体验,能够很好地支撑应用的搜索需求。