ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Backstage 搜索索引构建指南:Collator 的原理、配置与自定义实现

Backstage 搜索索引构建指南:Collator 的原理、配置与自定义实现 Backstage 搜索索引构建指南Collator 的原理、配置与自定义实现【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstageBackstage 的全局搜索能力依赖一个核心抽象——Collator整理器/采集器。本文将围绕 docs/features/search/collators.md 展开系统讲解 Collator 在搜索架构中的定位、开箱即用的 Catalog 与 TechDocs 两大内置 Collator 的安装与配置调度、过滤、批处理等参数并结合当前仓库源码plugins/search-backend-module-catalog 等印证其底层实现最后介绍社区 Collator 生态与编写自定义 Collator 的完整路径。读完本文你将具备在生产 Backstage 实例中按需裁剪、调优并扩展搜索索引的实战能力。Collator 在 Backstage Search 中的定位在动手配置之前先明确 Collator 在搜索体系中的角色。根据 Search ConceptsBackstage Search 并非一个自研搜索引擎而是连接你的 Backstage 实例与所选搜索引擎Elasticsearch、Lunr、Solr 等的接口层。在这条链路中Search Engine搜索引擎通过SearchEngine接口与具体引擎通信开箱即用的是一个基于 Lunr 的内存实现Query Translator查询翻译器把抽象查询搜索词、过滤器、文档类型翻译成具体搜索引擎的查询语言Documents and Indices文档与索引Document是可以被搜索到的内容的抽象至少包含title、text、locationURL字段索引是同类型文档的集合Collator采集器定义什么可以被搜索。它本质上是一个可读的文档对象流readable object stream负责采集并产出某一种类型的文档Decorator装饰器位于 Collator读流与 Indexer写流之间的转换流可在索引过程中为文档补充元数据、过滤文档甚至新增文档Scheduler调度器Backstage Search 采用定时全量重建索引的策略不同 Collator 可配置不同的刷新间隔architecture.md 明确将事件驱动、增量索引列为非目标。从架构目标看搜索能力被设计为任何插件都能向搜索暴露新内容而 Collator 正是实现这一目标的关键扩展点。开箱即用的两个内置 CollatorBackstage 为 Catalog软件目录与 TechDocs 两个场景各内置了一个 Collator。二者默认随后端安装启用若你的后端需要手动装配可按下面步骤操作。Catalog Collator为软件目录建立索引Catalog Collator 会索引目录中的全部实体Entity。安装时先从 Backstage 根目录添加依赖yarn --cwd packages/backend add backstage/plugin-search-backend-module-catalog然后在后端入口文件 packages/backend/src/index.ts 中注册插件const backend createBackend(); // Other plugins... // search plugin backend.add(import(backstage/plugin-search-backend)); // highlight-add-start backend.add(import(backstage/plugin-search-backend-module-catalog)); // highlight-add-end backend.start();从源码看这个模块通过新后端系统中的createBackendModule注册在registerInit中注入coreServicesauth、rootConfig、scheduler、searchIndexRegistryExtensionPoint与catalogServiceRef然后调用indexRegistry.addCollator(...)把DefaultCatalogCollatorFactory接入索引注册表见 module.ts。调度配置SchedulingCatalog Collator 的默认调度是每 10 分钟执行一次。你可以在app-config.yaml中通过search.collators.catalog.schedule覆盖search: collators: catalog: schedule: # same options as in SchedulerServiceTaskScheduleDefinition # supports cron, ISO duration, human duration as used in code initialDelay: { seconds: 90 } # supports cron, ISO duration, human duration as used in code frequency: { hours: 6 } # supports ISO duration, human duration as used in code timeout: { minutes: 3 }结合源码可以确认默认值的具体构成。在 config.ts 中export const defaults { schedule: { frequency: { minutes: 10 }, timeout: { minutes: 15 }, initialDelay: { seconds: 3 }, }, ... };即实际默认调度为频率 10 分钟、超时 15 分钟、初始延迟 3 秒。配置解析由readScheduleConfigOptions完成它读取search.collators.catalog.schedule并通过readSchedulerServiceTaskScheduleDefinitionFromConfig解析支持 cron 表达式、ISO 时长与代码中常用的人类可读时长配置非法时会抛出InputErrorconfig.ts。最终由scheduler.createScheduledTaskRunner(schedule)生成定时任务执行器。过滤配置Filtering你可能只想采集目录中的部分实体子集通过filter配置项即可实现。基础示例search: collators: catalog: filter: kind: [component, api] spec.lifecycle: production上述示例只会采集kind为component或api并且spec.lifecycle为production的实体多个条件之间是 AND 关系。更高级的过滤写法是使用过滤表达式数组数组内各组条件之间是 OR 关系search: collators: catalog: filter: - kind: [API] spec.type: openapi - kind: [Component] spec.lifecycle: experimental此示例会采集两类实体kind为api且spec.type为openapi的实体或者kind为component且spec.lifecycle为experimental的实体。原文档特别提示filter配置使用EntityFilterQuery语法实现。从 config.ts 可以看到filter被直接读取为EntityFilterQuery | undefined并透传给DefaultCatalogCollatorFactory。而在 DefaultCatalogCollatorFactory.ts 的execute()中该 filter 被放入QueryEntitiesInitialRequest通过catalog.queryEntities()分页拉取实体——也就是说过滤是在 Catalog 服务端执行的而不是在采集端做内存过滤。更多配置项locationTemplate 与 batchSize除了调度与过滤Catalog Collator 还支持两个重要参数详见 config.d.ts配置项说明默认值locationTemplate用于生成文档最终 URL 的模板字符串支持占位符:namespace、:kind、:name/catalog/:namespace/:kind/:namebatchSize每次向 Catalog 批量拉取的实体数量建议保持合理数值以免压垮 Catalog 或搜索后端500例如想自定义文档链接格式search: collators: catalog: locationTemplate: /software/:namespace/:kind/:name batchSize: 200在源码中locationTemplate的占位符替换发生在applyArgsToFormat方法里分别用实体的metadata.namespace缺省为default、kind、metadata.name的 URI 编码值替换:namespace、:kind、:name最终统一转为小写DefaultCatalogCollatorFactory.ts。源码级实现要点阅读DefaultCatalogCollatorFactory还可以得到几个有价值的实现细节文档类型标识工厂的type为software-catalog该值会写入每个文档供前端搜索结果组件按类型匹配展示游标分页execute()使用cursor游标循环调用catalog.queryEntities()每批batchSize个实体直到pageInfo.nextCursor为空——避免一次性把整个目录加载进内存权限集成工厂声明了visibilityPermission catalogEntityReadPermission并在查询时携带auth.getOwnServiceCredentials()的服务凭据保证索引过程遵守目录的权限模型实体转换器扩展点模块暴露了catalogCollatorExtensionPointmodule.ts允许通过setEntityTransformer自定义实体 → 文档的转换逻辑官方 README 给出了定制 transformer 的完整示例README.md可自由决定文档包含componentType、lifecycle、owner等额外字段。TechDocs Collator为文档建立索引TechDocs Collator 会索引 Catalog 中所有的 TechDocs 文档。安装与注册方式与 Catalog Collator 一致yarn --cwd packages/backend add backstage/plugin-search-backend-module-techdocsconst backend createBackend(); // Other plugins... // search plugin backend.add(import(backstage/plugin-search-backend)); // highlight-add-start backend.add(import(backstage/plugin-search-backend-module-techdocs)); // highlight-add-end backend.start();调度配置TechDocs Collator 的默认调度同样是每 10 分钟执行一次可通过search.collators.techdocs.schedule覆盖search: collators: techdocs: schedule: # same options as in SchedulerServiceTaskScheduleDefinition # supports cron, ISO duration, human duration as used in code initialDelay: { seconds: 90 } # supports cron, ISO duration, human duration as used in code frequency: { hours: 6 } # supports ISO duration, human duration as used in code timeout: { minutes: 3 }借助 Catalog Collator 扩展点做过滤TechDocs Collator 默认只采集 Catalog 中存在注解metadata.annotations.backstage.io/techdocs-ref的实体。如果希望进一步过滤官方提供两条路径都通过techDocsCollatorEntityFilterExtensionPoint扩展点实现collators.mdexport const exampleCustomCatalogFiltering createBackendModule({ pluginId: search, moduleId: search-techdocs-collator-entity-filter, register(reg) { reg.registerInit({ deps: { customCollatorFilter: techDocsCollatorEntityFilterExtensionPoint, }, async init({ customCollatorFilter }) { /* filtering by catalog params */ customCollatorFilter.setCustomCatalogApiFilters([ { kind: [API, Component, ...] }, { metadata: [...more filters] }, ]); /* filtering by a custom function */ customCollatorFilter.setEntityFilterFunction((entities: Entity[]) entities.filter( entity entity.metadata?.annotations?.abc xyz, ), ); }, }); }, });两种方式可并行使用setCustomCatalogApiFilters基于 Catalog 查询参数过滤与 Catalog Collator 的filter语法一致setEntityFilterFunction提供自定义过滤函数对已拉取的实体做内存级精确过滤例如按任意注解值筛选。社区 Collator 生态除内置的两个 Collator 外Backstage 社区还提供了多种现成的 Collator 模块覆盖常见的第三方内容源。下面列出当前文档中记录的社区包名可按需接入你的后端backstage-community/plugin-search-backend-module-explore索引 Explore 插件的探索内容backstage/plugin-search-backend-module-stack-overflow-collator索引 Stack Overflow 内容该包在本仓库 plugins/search-backend-module-stack-overflow-collator 中维护backstage-community/search-backend-module-adr索引 ADR架构决策记录插件的记录backstage-community/plugin-search-backend-module-announcements索引 Announcements 插件的公告内容backstage-community/plugin-search-backend-module-azure-devops索引 Azure DevOps 的 Wiki 文档backstage-community/plugin-search-backend-module-confluence-collator索引 Confluence 内容backstage-community/plugin-search-backend-module-github-discussions索引 GitHub Discussions 内容backstage-community/plugin-search-backend-module-report-portal索引 ReportPortal 内容。这些包的接入方式与内置 Collator 一致yarn add后在packages/backend/src/index.ts中backend.add(import(...))即可。编写自定义 Collator当内置与社区 Collator 都无法满足需求时你可以为任意数据源编写自己的 Collator。官方推荐使用脚手架模板详细教程见 Writing Custom Collators以下是核心路径。脚手架生成模块在 Backstage 根目录执行yarn new --select search-collator-module按提示输入模块 ID例如blog-posts模板会在plugins/search-backend-module-blog-posts/生成一个包含module.ts、BlogPostsCollatorFactory.ts、BlogPostsCollatorFactory.test.ts等文件的完整包并自动在后端注册backend.add(import(internal/plugin-search-backend-module-blog-posts));理解生成代码生成的module.ts负责把 Collator 接入搜索索引注册表并从配置读取可选调度缺省回退到每 10 分钟一次DEFAULT_SCHEDULE为频率 10 分钟、超时 15 分钟、初始延迟 3 秒import { coreServices, createBackendModule, readSchedulerServiceTaskScheduleDefinitionFromConfig, } from backstage/backend-plugin-api; import { searchIndexRegistryExtensionPoint } from backstage/plugin-search-backend-node/alpha; import { BlogPostsCollatorFactory } from ./collator/BlogPostsCollatorFactory; const DEFAULT_SCHEDULE { frequency: { minutes: 10 }, timeout: { minutes: 15 }, initialDelay: { seconds: 3 }, }; export const searchModuleBlogPosts createBackendModule({ pluginId: search, moduleId: blog-posts-collator, register({ registerInit }) { registerInit({ deps: { config: coreServices.rootConfig, logger: coreServices.logger, scheduler: coreServices.scheduler, indexRegistry: searchIndexRegistryExtensionPoint, }, async init({ config, logger, scheduler, indexRegistry }) { const scheduleConfig config .getOptionalConfig(search.collators.blogPosts) ?.getOptionalConfig(schedule); const schedule scheduleConfig ? readSchedulerServiceTaskScheduleDefinitionFromConfig(scheduleConfig) : DEFAULT_SCHEDULE; indexRegistry.addCollator({ schedule: scheduler.createScheduledTaskRunner(schedule), factory: BlogPostsCollatorFactory.fromConfig(config, { logger }), }); }, }); }, });生成的BlogPostsCollatorFactory.ts实现了DocumentCollatorFactory接口type属性声明文档类型getCollator()返回Readable.from(this.execute())execute()是一个 async generator逐条yield符合IndexableDocument的文档——每个文档至少必须包含title、text、location三个字段。实现数据抓取逻辑把占位的execute()替换成真实的数据抓取逻辑即可。例如从内部 API 拉取博客文章import { LoggerService } from backstage/backend-plugin-api; import { Config } from backstage/config; import { DocumentCollatorFactory, IndexableDocument, } from backstage/plugin-search-common; import { Readable } from node:stream; type BlogPost { id: string; title: string; body: string; author: string; }; export type BlogPostsCollatorFactoryOptions { logger: LoggerService; }; export class BlogPostsCollatorFactory implements DocumentCollatorFactory { public readonly type blog-posts; private readonly baseUrl: string; private readonly logger: LoggerService; static fromConfig( config: Config, options: BlogPostsCollatorFactoryOptions, ): BlogPostsCollatorFactory { const baseUrl config.getString(blogPosts.baseUrl); return new BlogPostsCollatorFactory(baseUrl, options); } private constructor( baseUrl: string, options: BlogPostsCollatorFactoryOptions, ) { this.baseUrl baseUrl; this.logger options.logger; } async getCollator(): PromiseReadable { return Readable.from(this.execute()); } private async *execute(): AsyncGeneratorIndexableDocument { this.logger.info(Collating documents for blog-posts); const response await fetch(${this.baseUrl}/blog-posts); const posts: BlogPost[] await response.json(); for (const post of posts) { yield { title: post.title, text: post.body, location: /blog-posts/${post.id}, }; } } }对于大规模数据集建议在execute()中使用游标分页逐页拉取避免一次性把所有记录载入内存——模式与内置 Catalog Collator 的游标循环完全一致见 custom-collators.md。测试与调度配置生成的测试文件使用TestPipeline来自backstage/plugin-search-backend-node运行 Collator 并校验输出mockServices提供配置与日志 mock。测试应断言工厂type正确、生成的文档字段符合预期title/text/location以及运行过程中无错误产生。自定义 Collator 的调度同样在app-config.yaml中配置键名为模块 ID 对应的驼峰形式search: collators: blogPosts: schedule: # same options as in SchedulerServiceTaskScheduleDefinition # supports cron, ISO duration, human duration as used in code initialDelay: { seconds: 90 } # supports cron, ISO duration, human duration as used in code frequency: { hours: 6 } # supports ISO duration, human duration as used in code timeout: { minutes: 3 }自定义搜索结果展示自定义 Collator 的搜索结果默认使用通用列表项自动渲染。若要定制展示可通过yarn new --select frontend-plugin-module脚手架一个前端模块插件 ID 填search模块 ID 填你的 collator 类型实现一个接收result含title、text、location字段的SearchResultListItem组件再用SearchResultListItemBlueprint.make注册并通过predicate: result result.type blog-posts匹配——注意该type必须与 Collator 工厂中声明的type属性一致详见 custom-collators.md。小结Collator 是 Backstage Search 从能搜到搜得准、搜得全的关键拼图内置的 Catalog 与 TechDocs Collator 让新实例开箱即得基础搜索能力schedule、filter、locationTemplate、batchSize等配置项在 config.d.ts 中有完整定义提供了对索引行为与性能的精细控制社区 Collator 覆盖了主流第三方内容源而DocumentCollatorFactory接口 脚手架模板让任何数据源都能在半小时内接入搜索。配合 Search 架构文档 与 Concepts 文档 阅读可以更完整地理解 Decorator、Query Translator、Search Engine 等相邻概念从而搭建出符合团队需求的搜索体验。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表