delete beta related how to guides
Signed-off-by: Emma Indal <emma.indahl@gmail.com>
This commit is contained in:
@@ -148,271 +148,6 @@ indexBuilder.addCollator({
|
||||
As shown above, you can add a catalog entity filter to narrow down what catalog
|
||||
entities are indexed by the search engine.
|
||||
|
||||
## How to migrate from Search Alpha to Beta
|
||||
|
||||
For the purposes of this guide, Search Beta version is defined as:
|
||||
|
||||
- **Search Plugin**: At least `v0.7.2`
|
||||
- **Search Backend Plugin**: At least `v0.4.6`
|
||||
- **Search Backend Node**: At least `v0.5.0`
|
||||
- **Search Common**: At least `v0.3.0`
|
||||
|
||||
In the Beta version, the Search Platform's indexing process has been rewritten
|
||||
as a stream pipeline in order to improve efficiency and performance on large
|
||||
sets of documents.
|
||||
|
||||
If you've not yet extended the Search Platform with custom code, and have
|
||||
instead taken advantage of default collators, decorators, and search engines
|
||||
provided by existing plugins, the migration process is fairly straightforward:
|
||||
|
||||
1. Upgrade to at least version `0.5.0` of
|
||||
`@backstage/plugin-search-backend-node`, as well as any backend plugins whose
|
||||
collators you are using (e.g. at least version `0.23.0` of
|
||||
`@backstage/plugin-catalog-backend` and/or version `0.14.1` of
|
||||
`@backstage/plugin-techdocs-backend`), as well as any search-engine specific
|
||||
plugin you are using (e.g. at least version `0.3.0` of
|
||||
`@backstage/plugin-search-backend-module-pg` or version `0.1.0` of
|
||||
`@backstage/plugin-search-backend-module-elasticsearch`).
|
||||
2. Then, make the following changes to your
|
||||
`/packages/backend/src/plugins/search.ts` file:
|
||||
|
||||
```diff
|
||||
-import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
|
||||
-import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
|
||||
+import { DefaultCatalogCollatorFactory } from '@backstage/plugin-catalog-backend';
|
||||
+import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
|
||||
// ...
|
||||
const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine });
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
- collator: DefaultCatalogCollator.fromConfig(env.config, {
|
||||
discovery: env.discovery,
|
||||
}),
|
||||
+ factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
|
||||
discovery: env.discovery,
|
||||
}),
|
||||
});
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
- collator: DefaultTechDocsCollator.fromConfig(env.config, {
|
||||
+ factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, {
|
||||
discovery: env.discovery,
|
||||
logger: env.logger,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
Any custom collators, decorators, or search engine implementations will require
|
||||
minor refactoring. Continue on for details.
|
||||
|
||||
### Rewriting alpha-style collators for beta
|
||||
|
||||
In alpha versions of the Backstage Search Platform, collators were classes that
|
||||
implemented an `execute` method which resolved an `IndexableDocument` array.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `execute` method
|
||||
is contained within an [object-mode][obj-mode] `Readable` stream where each
|
||||
object pushed onto the stream is of type `IndexableDocument`. Instances of this
|
||||
stream are instantiated by a factory class conforming to the
|
||||
`DocumentCollatorFactory` interface.
|
||||
|
||||
The optimal conversion strategy will vary depending on the collator's logic, but
|
||||
the simplest conversion can follow a process like this:
|
||||
|
||||
1. Rename your collator class to something like `YourCollatorFactory` and update
|
||||
it to implement `DocumentCollatorFactory` instead of `DocumentCollator`.
|
||||
2. Update its `execute` method so that it resolves
|
||||
`AsyncGenerator<YourIndexableDocument>` instead of `YourIndexableDocument[]`.
|
||||
3. Implement `DocumentCollatorFactory`'s `getCollator` method which resolves to
|
||||
`Readable.from(this.execute())` (which is a utility for creating [readable
|
||||
streams][read-stream] from [async generators][async-gen]).
|
||||
|
||||
```ts
|
||||
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
|
||||
import { Readable } from 'stream';
|
||||
export class YourCollatorFactory implements DocumentCollatorFactory {
|
||||
public readonly type: string = 'your-type';
|
||||
async *execute(): AsyncGenerator<YourIndexableDocument> {
|
||||
const widgets = await this.client.getWidgets();
|
||||
for (const widget of widgets) {
|
||||
yield {
|
||||
title: widget.name,
|
||||
location: widget.url,
|
||||
text: widget.description,
|
||||
};
|
||||
}
|
||||
}
|
||||
async getCollator() {
|
||||
return Readable.from(this.execute());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: it may be possible to simplify your collator dramatically! If your custom
|
||||
collator was previously using streams under the hood (for example, by reading
|
||||
newline delimited JSON from a local or remote file), you could just expose the
|
||||
stream directly via a simple factory class:
|
||||
|
||||
```ts
|
||||
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
|
||||
import { createReadStream } from 'fs';
|
||||
import { parse } from '@jsonlines/core';
|
||||
export class YourCollatorFactory implements DocumentCollatorFactory {
|
||||
public readonly type: string = 'your-type';
|
||||
async getCollator() {
|
||||
const parseStream = parse();
|
||||
return createReadStream('./documents.ndjson').pipe(parseStream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rewriting alpha-style decorators for beta
|
||||
|
||||
In alpha versions of the Backstage Search Platform, decorators were classes that
|
||||
implemented an `execute` method which took an `IndexableDocument` array as an
|
||||
argument, and resolved a modified array of the same type.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `execute` method
|
||||
is contained within an object-mode `Transform` stream which reads objects of
|
||||
type `IndexableDocument`, and writes objects of a conforming type. Similar to
|
||||
collators, instances of this stream are instantiated by a factory class
|
||||
conforming to the `DocumentDecoratorFactory` interface.
|
||||
|
||||
Although you can choose to implement a `Transform` stream from scratch, the
|
||||
`@backstage/plugin-search-backend-node` package provides a `DecoratorBase` class
|
||||
in order to simplify the developer experience. With this base class, all that's
|
||||
needed is to transfer your old decorator class logic into the base class' three
|
||||
methods (`initialize`, `decorate`, and `finalize`), and implement the factory
|
||||
class that instantiates the stream:
|
||||
|
||||
```ts
|
||||
import { DecoratorBase } from '@backstage/plugin-search-backend-node';
|
||||
export class YourDecorator extends DecoratorBase {
|
||||
async initialize() {
|
||||
// Setup logic. Performed once before any documents are consumed.
|
||||
}
|
||||
async decorate(
|
||||
document: YourIndexableDocument,
|
||||
): Promise<YourIndexableDocument | YourIndexableDocument[] | undefined> {
|
||||
// Perform transformation logic here.
|
||||
return document;
|
||||
}
|
||||
async finalize() {
|
||||
// Teardown logic. Performed once after all documents have been consumed.
|
||||
}
|
||||
}
|
||||
export class YourDecoratorFactory implements DocumentDecoratorFactory {
|
||||
async getDecorator() {
|
||||
return new YourDecorator();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the return type of the `decorate` method and how each can be used to
|
||||
different effect.
|
||||
|
||||
- By resolving a single `YourIndexableDocument` object, your decorator can be
|
||||
used to make simple transformations:
|
||||
|
||||
```ts
|
||||
class BooleanWidgetCoolnessDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Perform a simple, 1:1 transformation.
|
||||
widget.isCool = widget.isCool === 'true' ? true : false;
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- By resolving `undefined`, your decorator can filter out documents which
|
||||
shouldn't be in the index:
|
||||
|
||||
```ts
|
||||
class OnlyCoolWidgetsDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Perform a simple filter operation.
|
||||
return widget.isCool ? widget : undefined;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- By resolving an array of `YourIndexableDocument` objects, you can generate
|
||||
multiple documents based on the content of one:
|
||||
|
||||
```ts
|
||||
class WidgetByVariantDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Generate one widget doc per widget variant.
|
||||
return widget.variants.map(variant => {
|
||||
// Each widget doc is the given widget plus a "variant" property
|
||||
// pulled from a widget.variants string array.
|
||||
return {
|
||||
...widget,
|
||||
variant,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In alpha versions, a decorator had access to every `IndexableDocument`
|
||||
simultaneously. This is no longer possible in beta versions (precisely to make
|
||||
the indexing process more efficient and performant). You will need to modify
|
||||
your decorator's logic so that it does not need access to every document at
|
||||
once.
|
||||
|
||||
### Rewriting alpha-style search engines for beta
|
||||
|
||||
Search Engines are responsible for both querying and indexing documents to an
|
||||
underlying search engine technology. While the search engine query interface
|
||||
didn't change between alpha and beta versions, the indexing half of the
|
||||
interface _did_ change.
|
||||
|
||||
In alpha versions of the Backstage Search Platform, a search engine implemented
|
||||
an `index` method which took a `type` and an `IndexableDocument` array and was
|
||||
responsible for writing these documents to the underlying search engine.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `index` method is
|
||||
contained within an object-mode `Writable` stream which expects objects of type
|
||||
`IndexableDocument`. On the search engine class itself, the `index` method is
|
||||
replaced with a `getIndexer` factory method which still takes the `type`, but
|
||||
resolves an instance of the aforementioned `Writable` stream.
|
||||
|
||||
Although you can choose to implement a `Writable` stream from scratch, the
|
||||
`@backstage/plugin-search-backend-node` package provides a
|
||||
`BatchSearchEngineIndexer` class in order to simplify the developer experience.
|
||||
With this base class, which collects documents in batches of a configurable size
|
||||
on your behalf, all that's needed is to transfer your old `index` method logic
|
||||
into the base class' three methods (`initialize`, `index`, and `finalize`), and
|
||||
implement the factory method that instantiates the stream:
|
||||
|
||||
```ts
|
||||
import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';
|
||||
import { SearchEngine } from '@backstage/plugin-search-common';
|
||||
export class YourSearchEngineIndexer extends BatchSearchEngineIndexer {
|
||||
constructor({ type }: { type: string }) {
|
||||
// Customize the number of documents passed to the index method per batch.
|
||||
super({ batchSize: 500 });
|
||||
// An imaginary search engine indexing client.
|
||||
this.index = new SomeSearchEngineIndex({ indexName: type });
|
||||
}
|
||||
async initialize() {
|
||||
// Setup logic. Performed once before any documents are consumed.
|
||||
}
|
||||
async index(documents: IndexableDocument[]) {
|
||||
await this.index.batchOf(documents);
|
||||
}
|
||||
async finalize() {
|
||||
// Teardown logic. Performed once after all documents have been consumed.
|
||||
}
|
||||
}
|
||||
export class YourSearchEngine implements SearchEngine {
|
||||
async getIndexer(type: string) {
|
||||
return new YourSearchEngineIndexer({ type });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How to customize search results highlighting styling
|
||||
|
||||
The default highlighting styling for matched terms in search results is your
|
||||
|
||||
Reference in New Issue
Block a user