본문 바로가기
WIKI 기술 지식 베이스

Search 시작하기

원문 보기 위키 갱신

Search 시작하기 (이전 프론트엔드 시스템)

이전 프론트엔드 시스템을 사용하는 Backstage 앱에서 검색을 추가·구성하는 가이드예요.

출처: 문서

본문

:::info 이 문서는 여전히 이전 프론트엔드 시스템을 사용하는 Backstage 앱을 위한 것이에요. 앱이 새 프론트엔드 시스템을 사용한다면 현재 가이드를 읽으세요. :::

Search는 Backstage의 플러그인으로 동작하므로, Search를 사용하려면 Backstage를 사용해야 해요.

아직 Backstage를 설정하지 않았다면 여기에서 시작하세요.

npx @backstage/create-app을 사용했고 packages/app/src/components/search에 검색 페이지가 이미 정의되어 있다면, 아래의 Search 사용자 지정하기로 건너뛰세요.

프론트엔드에 Search 추가하기

Backstage 루트 디렉터리에서

yarn --cwd packages/app add @backstage/plugin-search @backstage/plugin-search-react

Backstage 앱에 새 packages/app/src/components/search/SearchPage.tsx 파일을 다음 내용으로 만들어요.

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 파일의 /search 라우트에 다음과 같이 바인딩해요.

import { SearchPage } from '@backstage/plugin-search';import { searchPage } from './components/search/SearchPage';const routes = (  <FlatRoutes>    <Route path="/search" element={<SearchPage />}>      {searchPage}    </Route>  </FlatRoutes>);

Search 모달 사용하기

Root.tsx에서 SidebarSearchModal 컴포넌트를 추가해요.

import { SidebarSearchModal } from '@backstage/plugin-search';export const Root = ({ children }: PropsWithChildren<{}>) => (  <SidebarPage>    <Sidebar>      <SidebarLogo />      <SidebarSearchModal />      <SidebarDivider />...

Root.tsx 사용에 대한 자세한 내용은 changelog를 참고하세요.

백엔드에 Search 추가하기

백엔드 앱에 다음 플러그인들을 추가해요.

Backstage 루트 디렉터리에서

yarn --cwd packages/backend add @backstage/plugin-search-backend @backstage/plugin-search-backend-module-pg @backstage/plugin-search-backend-module-catalog @backstage/plugin-search-backend-module-techdocs

그런 다음 다음 줄들을 추가해요.

packages/backend/src/index.ts

const backend = createBackend();// Other plugins...// search pluginbackend.add(import('@backstage/plugin-search-backend'));// search enginesbackend.add(import('@backstage/plugin-search-backend-module-pg'));// search collatorsbackend.add(import('@backstage/plugin-search-backend-module-catalog'));backend.add(import('@backstage/plugin-search-backend-module-techdocs'));backend.start();

위 설정으로 Search는 Lunr 인메모리 검색 엔진을 사용하지만, 데이터베이스로 Postgres를 설정했다면 Postgres를 검색 엔진으로 사용해요. 자세한 내용은 Search 엔진 문서를 참고하세요.

위 설정은 Catalog와 TechDocs 두 개의 콜레이터도 설정해 주며, 이 두 위치의 콘텐츠를 인덱싱해서 쉽게 검색할 수 있게 해줘요. 자세한 내용은 콜레이터 문서를 참고하세요.

Search 사용자 지정하기

프론트엔드

Search 플러그인 웹 라이브러리(@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>

Search 프론트엔드를 더 고급으로 사용자 지정하려면 'Search API를 직접 구현하는 방법'이나 '검색 결과 하이라이팅 스타일을 사용자 지정하는 방법' 같은 how-to 가이드도 참고하세요.

백엔드

Backstage Search는 그 자체가 검색 엔진은 아니에요. 대신 Backstage 인스턴스와 선택한 검색 엔진 사이의 인터페이스를 제공해요. 현재는 인메모리 검색 엔진인 Lunr와 Elasticsearch 두 가지만 지원해요. 이들을 Backstage 인스턴스에서 구성하는 방법에 대한 자세한 내용은 Search 엔진 문서를 참고하세요.

Backstage Search는 무엇이든 검색하는 데 사용할 수 있어요! Catalog 같은 플러그인은 인덱싱할 문서를 제공하는 기본 콜레이터(예: DefaultCatalogCollator)를 제공하며, 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는 예약(schedule)에 따라 인덱스를 구축하고 유지해요. 주어진 문서 유형에 대해 인덱스가 다시 구축되는 빈도를 변경할 수 있어요. 문서가 더 자주 또는 덜 자주 업데이트된다면 이렇게 하고 싶을 수 있어요. 이는 schedule 값에 전달할 예약된 SchedulerServiceTaskRunner를 구성해 처리할 수 있어요.

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,  }),});

:::note 인메모리 Lunr 검색 엔진을 사용한다면, 여러 검색 백엔드 노드를 실행할 때 일관성을 보장하기 위해 다음처럼 비분산(non-distributed) SchedulerServiceTaskRunner를 구현하고 싶을 거예요(또는 검색 플러그인이 SQLite 같은 비분산 데이터베이스를 사용하도록 구성할 수도 있어요). :::

import {  SchedulerServiceTaskRunner,  SchedulerServiceTaskInvocationDefinition,} from '@backstage/backend-plugin-api';const schedule: SchedulerServiceTaskRunner = {  run: async (task: SchedulerServiceTaskInvocationDefinition) => {    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,  }),});

Search 백엔드를 더 고급으로 사용자 지정하려면 'Software Catalog 또는 TechDocs 인덱스의 필드를 사용자 지정하는 방법' 같은 how-to 가이드도 참고하세요.

더 알아보기 (Learn more)