Skip to main content

搜索入门

搜索 "是Backstage的一个插件,因此需要使用Backstage才能使用 "搜索"。

如果您还没有设置Backstage,请启动这里.

如果您使用了 npx @backstage/create-app,并且在 > packages/app/src/components/search 中定义了搜索页面,请跳至 > 下面的 自定义搜索

在前台添加搜索功能

# From your Backstage root directory
yarn add --cwd packages/app @backstage/plugin-search @backstage/plugin-search-react

创建一个新的packages/app/src/components/search/SearchPage.tsx文件,内容如下:

import React from 'react';
import { Content, Header, Page } from '@backstage/core-components';
import { Grid, List, Card, CardContent } from '@material-ui/core';
import {
SearchBar,
SearchResult,
DefaultResultListItem,
SearchFilter,
} from '@backstage/plugin-search-react';
import { CatalogSearchResultListItem } from '@backstage/plugin-catalog';

export const searchPage = (
<Page themeId="home">
<Header title="Search" />
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<SearchBar />
</Grid>
<Grid item xs={3}>
<Card>
<CardContent>
<SearchFilter.Select
name="kind"
values={['Component', 'Template']}
/>
</CardContent>
<CardContent>
<SearchFilter.Checkbox
name="lifecycle"
values={['experimental', 'production']}
/>
</CardContent>
</Card>
</Grid>
<Grid item xs={9}>
<SearchResult>
{({ results }) => (
<List>
{results.map(result => {
switch (result.type) {
case 'software-catalog':
return (
<CatalogSearchResultListItem
key={result.document.location}
result={result.document}
highlight={result.highlight}
/>
);
default:
return (
<DefaultResultListItem
key={result.document.location}
result={result.document}
highlight={result.highlight}
/>
);
}
})}
</List>
)}
</SearchResult>
</Grid>
</Grid>
</Content>
</Page>
);

将上述搜索页面绑定到/search在您的packages/app/src/App.tsx文件,就像这样

import { SearchPage } from '@backstage/plugin-search';
import { searchPage } from './components/search/SearchPage';

const routes = (
<FlatRoutes>
<Route path="/search" element={<SearchPage />}>
{searchPage}
</Route>
</FlatRoutes>
);

使用搜索模式

Root.tsx添加SidebarSearchModal组件:

import { SidebarSearchModal } from '@backstage/plugin-search';

export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
<SidebarSearchModal />
<SidebarDivider />
...

有关使用Root.tsx请参阅更新日志.

在后端添加搜索功能

在后端应用程序中添加以下插件:

# From your Backstage root directory
yarn add --cwd packages/backend @backstage/plugin-search-backend @backstage/plugin-search-backend-node

创建一个packages/backend/src/plugins/search.ts文件,其中包含以下代码

import { useHotCleanup } from '@backstage/backend-common';
import { createRouter } from '@backstage/plugin-search-backend';
import {
IndexBuilder,
LunrSearchEngine,
} from '@backstage/plugin-search-backend-node';
import { PluginEnvironment } from '../types';
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
import { Router } from 'express';

export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const searchEngine = new LunrSearchEngine({
logger: env.logger,
});
const indexBuilder = new IndexBuilder({
logger: env.logger,
searchEngine,
});

const every10MinutesSchedule = env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 10 },
timeout: { minutes: 15 },
initialDelay: { seconds: 3 },
});

indexBuilder.addCollator({
schedule: every10MinutesSchedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
}),
});

const { scheduler } = await indexBuilder.build();

scheduler.start();
useHotCleanup(module, () => scheduler.stop());

return await createRouter({
engine: indexBuilder.getSearchEngine(),
logger: env.logger,
});
}

对您的packages/backend/src/index.ts锉刀

导入plugins/search文件:

import search from './plugins/search';

建立搜索环境:

const searchEnv = useHotMemoize(module, () => createEnv('search'));

在路由器上注册搜索服务:

apiRouter.use('/search', await search(searchEnv));

定制搜索

前端

搜索插件网络库 (@backstage/plugin-search-react) 将几种默认过滤器类型作为静态属性公开,包括<SearchFilter.Select /><SearchFilter.Checkbox />这些功能允许您提供与Backstage实例相关的值,这些值在被选中后会被传递到后端。

<CardContent>
<SearchFilter.Select
name="kind"
values={['Component', 'Template']}
/>
</CardContent>
<CardContent>
<SearchFilter.Checkbox
name="lifecycle"
values={['production', 'experimental']}
/>
</CardContent>

如果您有高级过滤器需求,可以像这样指定自己的过滤器组件(当然,我们也欢迎您提供新的核心过滤器):

import { useSearch, SearchFilter } from '@backstage/plugin-search-react';

const MyCustomFilter = () => {
// Note: filters contain filter data from other filter components. Be sure
// not to clobber other filters' data!
const { filters, setFilters } = useSearch();

return (/* ... */);
};

// Which could be rendered like this:
<SearchFilter component={MyCustomFilter} />

对于搜索结果来说,首先突出显示用于返回结果的信息是一种很好的做法!下面的代码重点说明了如何使用<CatalogSearchResultListItem />组件为例:

<SearchResult>
{({ results }) => (
<List>
{results.map(result => {
// result.type is the index type defined by the collator.
switch (result.type) {
case 'software-catalog':
return (
<CatalogSearchResultListItem
key={result.document.location}
result={result.document}
highlight={result.highlight}
/>
);
// ...
}
})}
</List>
)}
</SearchResult>

有关搜索前端的更高级自定义功能,请参阅如何实现自己的搜索 API如何自定义搜索结果高亮样式等指南。

后端

Backstage Search 本身并不是一个搜索引擎,而是在 Backstage 实例和一个搜索引擎目前,我们只支持两种引擎,一种是名为 Lunr 的内存搜索引擎,另一种是 Elasticsearch。 请参见搜索引擎有关如何在 Backstage 实例中配置这些功能的更多信息,请参阅文档。

Backstage搜索可用于对任何内容进行强力搜索!目录等插件提供默认的拼版机例如默认目录整理器) 负责提供文件将被索引您可以使用IndexBuilder像这样

const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine });

const every10MinutesSchedule = env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 10 },
timeout: { minutes: 15 },
initialDelay: { seconds: 3 },
});

const everyHourSchedule = env.scheduler.createScheduledTaskRunner({
frequency: { hours: 1 },
timeout: { minutes: 90 },
initialDelay: { seconds: 3 },
});

indexBuilder.addCollator({
schedule: every10MinutesSchedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
}),
});

indexBuilder.addCollator({
schedule: everyHourSchedule,
factory: new MyCustomCollatorFactory(),
});

Backstage Search 建立并维护其索引按计划您可以更改为特定类型文档重建索引的频率。 如果文档更新频率较高或较低,您可能需要这样做。 您可以通过配置计划的TaskRunner进入schedule值,就像这样:

const every10MinutesSchedule = env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 10 },
timeout: { minutes: 15 },
initialDelay: { seconds: 3 },
});

indexBuilder.addCollator({
schedule: every10MinutesSchedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
}),
});

注意:如果您使用的是内存中的 Lunr 搜索引擎,您可能需要实现一个非分布式的TaskRunner这样,如果运行多个搜索后端节点,就可以确保一致性(或者,也可以配置搜索插件使用非分布式数据库,如SQLite):

import { TaskInvocationDefinition, TaskRunner } from '@backstage/backend-tasks';

const schedule: TaskRunner = {
run: async (task: TaskInvocationDefinition) => {
const startRefresh = async () => {
while (!task.signal?.aborted) {
try {
await task.fn(task.signal);
} catch {
// ignore intentionally
}

await new Promise(resolve => setTimeout(resolve, 600 * 1000));
}
};
startRefresh();
},
};

indexBuilder.addCollator({
schedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
}),
});

有关搜索后端更高级的自定义功能,请参阅使用指南,如如何为 TechDocs 文档编制索引如何限制在软件目录中搜索的内容