@backstage/plugin-search-backend-module-elasticsearch 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.cjs.js +24 -27
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -27,12 +27,13 @@ class ElasticSearchSearchEngine {
|
|
|
27
27
|
this.logger = logger;
|
|
28
28
|
this.indexSeparator = "-index__";
|
|
29
29
|
}
|
|
30
|
-
static async fromConfig({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
static async fromConfig(options) {
|
|
31
|
+
const {
|
|
32
|
+
logger,
|
|
33
|
+
config,
|
|
34
|
+
aliasPostfix = `search`,
|
|
35
|
+
indexPrefix = ``
|
|
36
|
+
} = options;
|
|
36
37
|
return new ElasticSearchSearchEngine(await ElasticSearchSearchEngine.constructElasticSearchClient(logger, config.getConfig("search.elasticsearch")), aliasPostfix, indexPrefix, logger);
|
|
37
38
|
}
|
|
38
39
|
static async constructElasticSearchClient(logger, config) {
|
|
@@ -91,27 +92,23 @@ class ElasticSearchSearchEngine {
|
|
|
91
92
|
} : {}
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
|
-
translator({
|
|
95
|
-
term,
|
|
96
|
-
filters = {},
|
|
97
|
-
types,
|
|
98
|
-
pageCursor
|
|
99
|
-
}) {
|
|
95
|
+
translator(query) {
|
|
96
|
+
const { term, filters = {}, types, pageCursor } = query;
|
|
100
97
|
const filter = Object.entries(filters).filter(([_, value]) => Boolean(value)).map(([key, value]) => {
|
|
101
98
|
if (["string", "number", "boolean"].includes(typeof value)) {
|
|
102
|
-
return esb__default[
|
|
99
|
+
return esb__default["default"].matchQuery(key, value.toString());
|
|
103
100
|
}
|
|
104
101
|
if (Array.isArray(value)) {
|
|
105
|
-
return esb__default[
|
|
102
|
+
return esb__default["default"].boolQuery().should(value.map((it) => esb__default["default"].matchQuery(key, it.toString())));
|
|
106
103
|
}
|
|
107
104
|
this.logger.error("Failed to query, unrecognized filter type", key, value);
|
|
108
105
|
throw new Error("Failed to add filters to query. Unrecognized filter type");
|
|
109
106
|
});
|
|
110
|
-
const
|
|
107
|
+
const esbQuery = isBlank(term) ? esb__default["default"].matchAllQuery() : esb__default["default"].multiMatchQuery(["*"], term).fuzziness("auto").minimumShouldMatch(1);
|
|
111
108
|
const pageSize = 25;
|
|
112
|
-
const {page} = decodePageCursor(pageCursor);
|
|
109
|
+
const { page } = decodePageCursor(pageCursor);
|
|
113
110
|
return {
|
|
114
|
-
elasticSearchQuery: esb__default[
|
|
111
|
+
elasticSearchQuery: esb__default["default"].requestBodySearch().query(esb__default["default"].boolQuery().filter(filter).must([esbQuery])).from(page * pageSize).size(pageSize).toJSON(),
|
|
115
112
|
documentTypes: types,
|
|
116
113
|
pageSize
|
|
117
114
|
};
|
|
@@ -137,7 +134,7 @@ class ElasticSearchSearchEngine {
|
|
|
137
134
|
datasource: documents,
|
|
138
135
|
onDocument() {
|
|
139
136
|
return {
|
|
140
|
-
index: {_index: index}
|
|
137
|
+
index: { _index: index }
|
|
141
138
|
};
|
|
142
139
|
},
|
|
143
140
|
refreshOnCompletion: index
|
|
@@ -146,8 +143,8 @@ class ElasticSearchSearchEngine {
|
|
|
146
143
|
await this.elasticSearchClient.indices.updateAliases({
|
|
147
144
|
body: {
|
|
148
145
|
actions: [
|
|
149
|
-
{remove: {index: this.constructIndexName(type, "*"), alias}},
|
|
150
|
-
{add: {index, alias}}
|
|
146
|
+
{ remove: { index: this.constructIndexName(type, "*"), alias } },
|
|
147
|
+
{ add: { index, alias } }
|
|
151
148
|
]
|
|
152
149
|
}
|
|
153
150
|
});
|
|
@@ -172,18 +169,18 @@ class ElasticSearchSearchEngine {
|
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
171
|
async query(query) {
|
|
175
|
-
const {elasticSearchQuery, documentTypes, pageSize} = this.translator(query);
|
|
172
|
+
const { elasticSearchQuery, documentTypes, pageSize } = this.translator(query);
|
|
176
173
|
const queryIndices = documentTypes ? documentTypes.map((it) => this.constructSearchAlias(it)) : this.constructSearchAlias("*");
|
|
177
174
|
try {
|
|
178
175
|
const result = await this.elasticSearchClient.search({
|
|
179
176
|
index: queryIndices,
|
|
180
177
|
body: elasticSearchQuery
|
|
181
178
|
});
|
|
182
|
-
const {page} = decodePageCursor(query.pageCursor);
|
|
179
|
+
const { page } = decodePageCursor(query.pageCursor);
|
|
183
180
|
const hasNextPage = result.body.hits.total.value > page * pageSize;
|
|
184
181
|
const hasPreviousPage = page > 0;
|
|
185
|
-
const nextPageCursor = hasNextPage ? encodePageCursor({page: page + 1}) : void 0;
|
|
186
|
-
const previousPageCursor = hasPreviousPage ? encodePageCursor({page: page - 1}) : void 0;
|
|
182
|
+
const nextPageCursor = hasNextPage ? encodePageCursor({ page: page + 1 }) : void 0;
|
|
183
|
+
const previousPageCursor = hasPreviousPage ? encodePageCursor({ page: page - 1 }) : void 0;
|
|
187
184
|
return {
|
|
188
185
|
results: result.body.hits.hits.map((d) => ({
|
|
189
186
|
type: this.getTypeFromIndex(d._index),
|
|
@@ -194,7 +191,7 @@ class ElasticSearchSearchEngine {
|
|
|
194
191
|
};
|
|
195
192
|
} catch (e) {
|
|
196
193
|
this.logger.error(`Failed to query documents for indices ${queryIndices}`, e);
|
|
197
|
-
return Promise.reject({results: []});
|
|
194
|
+
return Promise.reject({ results: [] });
|
|
198
195
|
}
|
|
199
196
|
}
|
|
200
197
|
constructIndexName(type, postFix) {
|
|
@@ -210,13 +207,13 @@ class ElasticSearchSearchEngine {
|
|
|
210
207
|
}
|
|
211
208
|
function decodePageCursor(pageCursor) {
|
|
212
209
|
if (!pageCursor) {
|
|
213
|
-
return {page: 0};
|
|
210
|
+
return { page: 0 };
|
|
214
211
|
}
|
|
215
212
|
return {
|
|
216
213
|
page: Number(Buffer.from(pageCursor, "base64").toString("utf-8"))
|
|
217
214
|
};
|
|
218
215
|
}
|
|
219
|
-
function encodePageCursor({page}) {
|
|
216
|
+
function encodePageCursor({ page }) {
|
|
220
217
|
return Buffer.from(`${page}`, "utf-8").toString("base64");
|
|
221
218
|
}
|
|
222
219
|
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n awsGetCredentials,\n createAWSConnection,\n} from '@acuris/aws-es-connection';\nimport { Config } from '@backstage/config';\nimport {\n IndexableDocument,\n SearchEngine,\n SearchQuery,\n SearchResultSet,\n} from '@backstage/search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport esb from 'elastic-builder';\nimport { isEmpty, isNaN as nan, isNumber } from 'lodash';\nimport { Logger } from 'winston';\n\nexport type ConcreteElasticSearchQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\ntype ElasticSearchQueryTranslator = (\n query: SearchQuery,\n) => ConcreteElasticSearchQuery;\n\ntype ElasticSearchOptions = {\n logger: Logger;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\n};\n\ntype ElasticSearchResult = {\n _index: string;\n _type: string;\n _score: number;\n _source: IndexableDocument;\n};\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\nfunction isBlank(str: string) {\n return (isEmpty(str) && !isNumber(str)) || nan(str);\n}\n\nexport class ElasticSearchSearchEngine implements SearchEngine {\n constructor(\n private readonly elasticSearchClient: Client,\n private readonly aliasPostfix: string,\n private readonly indexPrefix: string,\n private readonly logger: Logger,\n ) {}\n\n static async fromConfig({\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n }: ElasticSearchOptions) {\n return new ElasticSearchSearchEngine(\n await ElasticSearchSearchEngine.constructElasticSearchClient(\n logger,\n config.getConfig('search.elasticsearch'),\n ),\n aliasPostfix,\n indexPrefix,\n logger,\n );\n }\n\n private static async constructElasticSearchClient(\n logger: Logger,\n config?: Config,\n ) {\n if (!config) {\n throw new Error('No elastic search config found');\n }\n\n const clientOptionsConfig = config.getOptionalConfig('clientOptions');\n const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl');\n\n if (config.getOptionalString('provider') === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n const authConfig = config.getConfig('auth');\n return new Client({\n cloud: {\n id: config.getString('cloudId'),\n },\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n if (config.getOptionalString('provider') === 'aws') {\n logger.info('Initializing AWS ElasticSearch search engine.');\n const awsCredentials = await awsGetCredentials();\n const AWSConnection = createAWSConnection(awsCredentials);\n return new Client({\n node: config.getString('node'),\n ...AWSConnection,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n logger.info('Initializing ElasticSearch search engine.');\n const authConfig = config.getOptionalConfig('auth');\n const auth =\n authConfig &&\n (authConfig.has('apiKey')\n ? {\n apiKey: authConfig.getString('apiKey'),\n }\n : {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n });\n return new Client({\n node: config.getString('node'),\n auth,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n\n protected translator({\n term,\n filters = {},\n types,\n pageCursor,\n }: SearchQuery): ConcreteElasticSearchQuery {\n const filter = Object.entries(filters)\n .filter(([_, value]) => Boolean(value))\n .map(([key, value]: [key: string, value: any]) => {\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n return esb.matchQuery(key, value.toString());\n }\n if (Array.isArray(value)) {\n return esb\n .boolQuery()\n .should(value.map(it => esb.matchQuery(key, it.toString())));\n }\n this.logger.error(\n 'Failed to query, unrecognized filter type',\n key,\n value,\n );\n throw new Error(\n 'Failed to add filters to query. Unrecognized filter type',\n );\n });\n const query = isBlank(term)\n ? esb.matchAllQuery()\n : esb\n .multiMatchQuery(['*'], term)\n .fuzziness('auto')\n .minimumShouldMatch(1);\n const pageSize = 25;\n const { page } = decodePageCursor(pageCursor);\n\n return {\n elasticSearchQuery: esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).must([query]))\n .from(page * pageSize)\n .size(pageSize)\n .toJSON(),\n documentTypes: types,\n pageSize,\n };\n }\n\n setTranslator(translator: ElasticSearchQueryTranslator) {\n this.translator = translator;\n }\n\n async index(type: string, documents: IndexableDocument[]): Promise<void> {\n this.logger.info(\n `Started indexing ${documents.length} documents for index ${type}`,\n );\n const startTimestamp = process.hrtime();\n const alias = this.constructSearchAlias(type);\n const index = this.constructIndexName(type, `${Date.now()}`);\n try {\n const aliases = await this.elasticSearchClient.cat.aliases({\n format: 'json',\n name: alias,\n });\n const removableIndices = aliases.body.map(\n (r: Record<string, any>) => r.index,\n );\n\n await this.elasticSearchClient.indices.create({\n index,\n });\n const result = await this.elasticSearchClient.helpers.bulk({\n datasource: documents,\n onDocument() {\n return {\n index: { _index: index },\n };\n },\n refreshOnCompletion: index,\n });\n\n this.logger.info(\n `Indexing completed for index ${type} in ${duration(startTimestamp)}`,\n result,\n );\n await this.elasticSearchClient.indices.updateAliases({\n body: {\n actions: [\n { remove: { index: this.constructIndexName(type, '*'), alias } },\n { add: { index, alias } },\n ],\n },\n });\n\n this.logger.info('Removing stale search indices', removableIndices);\n if (removableIndices.length) {\n await this.elasticSearchClient.indices.delete({\n index: removableIndices,\n });\n }\n } catch (e) {\n this.logger.error(`Failed to index documents for type ${type}`, e);\n const response = await this.elasticSearchClient.indices.exists({\n index,\n });\n const indexCreated = response.body;\n if (indexCreated) {\n this.logger.info(`Removing created index ${index}`);\n await this.elasticSearchClient.indices.delete({\n index,\n });\n }\n }\n }\n\n async query(query: SearchQuery): Promise<SearchResultSet> {\n const { elasticSearchQuery, documentTypes, pageSize } =\n this.translator(query);\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClient.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > page * pageSize;\n const hasPreviousPage = page > 0;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n return {\n results: result.body.hits.hits.map((d: ElasticSearchResult) => ({\n type: this.getTypeFromIndex(d._index),\n document: d._source,\n })),\n nextPageCursor,\n previousPageCursor,\n };\n } catch (e) {\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n e,\n );\n return Promise.reject({ results: [] });\n }\n }\n\n private readonly indexSeparator = '-index__';\n\n private constructIndexName(type: string, postFix: string) {\n return `${this.indexPrefix}${type}${this.indexSeparator}${postFix}`;\n }\n\n private getTypeFromIndex(index: string) {\n return index\n .substring(this.indexPrefix.length)\n .split(this.indexSeparator)[0];\n }\n\n private constructSearchAlias(type: string) {\n const postFix = this.aliasPostfix ? `__${this.aliasPostfix}` : '';\n return `${this.indexPrefix}${type}${postFix}`;\n }\n}\n\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n"],"names":["isEmpty","isNumber","nan","Client","awsGetCredentials","createAWSConnection","esb"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n awsGetCredentials,\n createAWSConnection,\n} from '@acuris/aws-es-connection';\nimport { Config } from '@backstage/config';\nimport {\n IndexableDocument,\n SearchEngine,\n SearchQuery,\n SearchResultSet,\n} from '@backstage/search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport esb from 'elastic-builder';\nimport { isEmpty, isNaN as nan, isNumber } from 'lodash';\nimport { Logger } from 'winston';\n\nexport type ConcreteElasticSearchQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\ntype ElasticSearchQueryTranslator = (\n query: SearchQuery,\n) => ConcreteElasticSearchQuery;\n\ntype ElasticSearchOptions = {\n logger: Logger;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\n};\n\ntype ElasticSearchResult = {\n _index: string;\n _type: string;\n _score: number;\n _source: IndexableDocument;\n};\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\nfunction isBlank(str: string) {\n return (isEmpty(str) && !isNumber(str)) || nan(str);\n}\n\n/**\n * @public\n */\nexport class ElasticSearchSearchEngine implements SearchEngine {\n constructor(\n private readonly elasticSearchClient: Client,\n private readonly aliasPostfix: string,\n private readonly indexPrefix: string,\n private readonly logger: Logger,\n ) {}\n\n static async fromConfig(options: ElasticSearchOptions) {\n const {\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n } = options;\n\n return new ElasticSearchSearchEngine(\n await ElasticSearchSearchEngine.constructElasticSearchClient(\n logger,\n config.getConfig('search.elasticsearch'),\n ),\n aliasPostfix,\n indexPrefix,\n logger,\n );\n }\n\n private static async constructElasticSearchClient(\n logger: Logger,\n config?: Config,\n ) {\n if (!config) {\n throw new Error('No elastic search config found');\n }\n\n const clientOptionsConfig = config.getOptionalConfig('clientOptions');\n const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl');\n\n if (config.getOptionalString('provider') === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n const authConfig = config.getConfig('auth');\n return new Client({\n cloud: {\n id: config.getString('cloudId'),\n },\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n if (config.getOptionalString('provider') === 'aws') {\n logger.info('Initializing AWS ElasticSearch search engine.');\n const awsCredentials = await awsGetCredentials();\n const AWSConnection = createAWSConnection(awsCredentials);\n return new Client({\n node: config.getString('node'),\n ...AWSConnection,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n logger.info('Initializing ElasticSearch search engine.');\n const authConfig = config.getOptionalConfig('auth');\n const auth =\n authConfig &&\n (authConfig.has('apiKey')\n ? {\n apiKey: authConfig.getString('apiKey'),\n }\n : {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n });\n return new Client({\n node: config.getString('node'),\n auth,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n });\n }\n\n protected translator(query: SearchQuery): ConcreteElasticSearchQuery {\n const { term, filters = {}, types, pageCursor } = query;\n\n const filter = Object.entries(filters)\n .filter(([_, value]) => Boolean(value))\n .map(([key, value]: [key: string, value: any]) => {\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n return esb.matchQuery(key, value.toString());\n }\n if (Array.isArray(value)) {\n return esb\n .boolQuery()\n .should(value.map(it => esb.matchQuery(key, it.toString())));\n }\n this.logger.error(\n 'Failed to query, unrecognized filter type',\n key,\n value,\n );\n throw new Error(\n 'Failed to add filters to query. Unrecognized filter type',\n );\n });\n const esbQuery = isBlank(term)\n ? esb.matchAllQuery()\n : esb\n .multiMatchQuery(['*'], term)\n .fuzziness('auto')\n .minimumShouldMatch(1);\n const pageSize = 25;\n const { page } = decodePageCursor(pageCursor);\n\n return {\n elasticSearchQuery: esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).must([esbQuery]))\n .from(page * pageSize)\n .size(pageSize)\n .toJSON(),\n documentTypes: types,\n pageSize,\n };\n }\n\n setTranslator(translator: ElasticSearchQueryTranslator) {\n this.translator = translator;\n }\n\n async index(type: string, documents: IndexableDocument[]): Promise<void> {\n this.logger.info(\n `Started indexing ${documents.length} documents for index ${type}`,\n );\n const startTimestamp = process.hrtime();\n const alias = this.constructSearchAlias(type);\n const index = this.constructIndexName(type, `${Date.now()}`);\n try {\n const aliases = await this.elasticSearchClient.cat.aliases({\n format: 'json',\n name: alias,\n });\n const removableIndices = aliases.body.map(\n (r: Record<string, any>) => r.index,\n );\n\n await this.elasticSearchClient.indices.create({\n index,\n });\n const result = await this.elasticSearchClient.helpers.bulk({\n datasource: documents,\n onDocument() {\n return {\n index: { _index: index },\n };\n },\n refreshOnCompletion: index,\n });\n\n this.logger.info(\n `Indexing completed for index ${type} in ${duration(startTimestamp)}`,\n result,\n );\n await this.elasticSearchClient.indices.updateAliases({\n body: {\n actions: [\n { remove: { index: this.constructIndexName(type, '*'), alias } },\n { add: { index, alias } },\n ],\n },\n });\n\n this.logger.info('Removing stale search indices', removableIndices);\n if (removableIndices.length) {\n await this.elasticSearchClient.indices.delete({\n index: removableIndices,\n });\n }\n } catch (e) {\n this.logger.error(`Failed to index documents for type ${type}`, e);\n const response = await this.elasticSearchClient.indices.exists({\n index,\n });\n const indexCreated = response.body;\n if (indexCreated) {\n this.logger.info(`Removing created index ${index}`);\n await this.elasticSearchClient.indices.delete({\n index,\n });\n }\n }\n }\n\n async query(query: SearchQuery): Promise<SearchResultSet> {\n const { elasticSearchQuery, documentTypes, pageSize } =\n this.translator(query);\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClient.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > page * pageSize;\n const hasPreviousPage = page > 0;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n return {\n results: result.body.hits.hits.map((d: ElasticSearchResult) => ({\n type: this.getTypeFromIndex(d._index),\n document: d._source,\n })),\n nextPageCursor,\n previousPageCursor,\n };\n } catch (e) {\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n e,\n );\n return Promise.reject({ results: [] });\n }\n }\n\n private readonly indexSeparator = '-index__';\n\n private constructIndexName(type: string, postFix: string) {\n return `${this.indexPrefix}${type}${this.indexSeparator}${postFix}`;\n }\n\n private getTypeFromIndex(index: string) {\n return index\n .substring(this.indexPrefix.length)\n .split(this.indexSeparator)[0];\n }\n\n private constructSearchAlias(type: string) {\n const postFix = this.aliasPostfix ? `__${this.aliasPostfix}` : '';\n return `${this.indexPrefix}${type}${postFix}`;\n }\n}\n\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n"],"names":["isEmpty","isNumber","nan","Client","awsGetCredentials","createAWSConnection","esb"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,15 +15,18 @@ declare type ElasticSearchOptions = {
|
|
|
15
15
|
aliasPostfix?: string;
|
|
16
16
|
indexPrefix?: string;
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
18
21
|
declare class ElasticSearchSearchEngine implements SearchEngine {
|
|
19
22
|
private readonly elasticSearchClient;
|
|
20
23
|
private readonly aliasPostfix;
|
|
21
24
|
private readonly indexPrefix;
|
|
22
25
|
private readonly logger;
|
|
23
26
|
constructor(elasticSearchClient: Client, aliasPostfix: string, indexPrefix: string, logger: Logger);
|
|
24
|
-
static fromConfig(
|
|
27
|
+
static fromConfig(options: ElasticSearchOptions): Promise<ElasticSearchSearchEngine>;
|
|
25
28
|
private static constructElasticSearchClient;
|
|
26
|
-
protected translator(
|
|
29
|
+
protected translator(query: SearchQuery): ConcreteElasticSearchQuery;
|
|
27
30
|
setTranslator(translator: ElasticSearchQueryTranslator): void;
|
|
28
31
|
index(type: string, documents: IndexableDocument[]): Promise<void>;
|
|
29
32
|
query(query: SearchQuery): Promise<SearchResultSet>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-search-backend-module-elasticsearch",
|
|
3
3
|
"description": "A module for the search backend that implements search using ElasticSearch",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"winston": "^3.2.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@backstage/backend-common": "^0.9.
|
|
34
|
-
"@backstage/cli": "^0.
|
|
33
|
+
"@backstage/backend-common": "^0.9.13",
|
|
34
|
+
"@backstage/cli": "^0.10.1",
|
|
35
35
|
"@elastic/elasticsearch-mock": "^0.3.0"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"testEnvironment": "node"
|
|
43
43
|
},
|
|
44
44
|
"configSchema": "config.d.ts",
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "562be0b43016294e27af3ad024191bb86b13b1c1"
|
|
46
46
|
}
|