17 KiB
17 KiB
GlobalSearch - 全局搜索模块
模块概述
GlobalSearch 是 OneApp 的全局搜索模块,提供了跨模块的统一搜索功能。该模块支持多种内容类型的搜索,包括智能搜索建议、搜索历史管理、搜索结果优化等功能,为用户提供高效、精准的搜索体验。
核心功能
1. 跨模块内容搜索
- 统一搜索入口:提供全局统一的搜索接口
- 多模块索引:聚合各模块的可搜索内容
- 内容分类:按类型分类搜索结果
- 权限控制:基于用户权限过滤搜索结果
2. 智能搜索建议
- 实时建议:输入时实时提供搜索建议
- 热门搜索:展示热门搜索关键词
- 个性化推荐:基于用户行为的个性化建议
- 拼写纠错:智能纠正搜索词拼写错误
3. 搜索历史管理
- 历史记录:保存用户搜索历史
- 快速访问:快速访问历史搜索结果
- 清理管理:支持清理搜索历史
- 隐私保护:敏感搜索历史加密存储
4. 搜索结果优化
- 相关性排序:按相关性智能排序
- 结果聚合:相似结果智能聚合
- 高亮显示:关键词高亮显示
- 分页加载:大量结果分页展示
技术架构
架构设计
┌─────────────────────────────────────┐
│ 搜索界面层 │
│ (Search UI Components) │
├─────────────────────────────────────┤
│ GlobalSearch 模块 │
│ ┌──────────┬──────────┬──────────┐ │
│ │ 搜索引擎 │ 索引管理 │ 结果处理 │ │
│ ├──────────┼──────────┼──────────┤ │
│ │ 建议系统 │ 历史管理 │ 缓存层 │ │
│ └──────────┴──────────┴──────────┘ │
├─────────────────────────────────────┤
│ 模块搜索接口 │
│ ┌──────────┬──────────┬──────────┐ │
│ │ 车辆模块 │ 订单模块 │ 设置模块 │ │
│ └──────────┴──────────┴──────────┘ │
├─────────────────────────────────────┤
│ 数据存储层 │
│ (Local DB + Remote Index) │
└─────────────────────────────────────┘
核心组件
1. 通用搜索组件 (GlobalSearchCommonWidget)
基于真实项目代码的通用搜索组件:
/// 全局搜索通用组件
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. 搜索组件实现
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: 搜索结果组件
数据模型
搜索查询模型
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 // 字母顺序
}
搜索结果模型
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;
}
搜索建议模型
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 接口
搜索接口
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);
}
索引管理接口
abstract class SearchIndexService {
// 更新搜索索引
Future<ApiResponse<bool>> updateSearchIndex(UpdateIndexRequest request);
// 删除搜索索引
Future<ApiResponse<bool>> deleteSearchIndex(DeleteIndexRequest request);
// 获取索引状态
Future<ApiResponse<IndexStatus>> getIndexStatus(String moduleId);
}
搜索提供者接口
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);
}
配置管理
搜索配置
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,
},
);
}
索引配置
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,
},
);
}
使用示例
基本搜索功能
// 初始化全局搜索
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}');
}
搜索建议功能
// 获取输入建议
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(', ')}');
搜索历史管理
// 添加搜索记录
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();
注册搜索提供者
// 实现搜索提供者
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());
测试策略
单元测试
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'));
});
});
集成测试
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);
});
});
性能优化
搜索性能优化
- 索引优化:使用倒排索引提高搜索速度
- 缓存策略:热门搜索结果缓存
- 分页加载:大结果集分页加载
- 异步处理:搜索操作异步处理
内存优化
- 结果限制:限制搜索结果数量
- 懒加载:搜索结果懒加载
- 对象池:复用搜索对象
- 内存回收:及时回收不用的搜索数据
算法和策略
相关性算法
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 提供了强大的全局搜索能力,通过统一的搜索接口、智能的搜索建议、完善的历史管理和优化的搜索结果,为用户提供了高效、精准的搜索体验。该模块的设计充分考虑了可扩展性、性能优化和用户体验,能够很好地支撑应用的搜索需求。