@vegan-friendly/strapi-plugin-elasticsearch 0.2.8 → 0.2.9
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/dist/package.json +1 -1
- package/dist/server/content-types/tasks.js +3 -3
- package/dist/server/index.d.ts +4 -2
- package/dist/server/services/index.d.ts +4 -2
- package/dist/server/services/perform-indexing.d.ts +2 -2
- package/dist/server/services/perform-indexing.js +48 -17
- package/dist/server/services/schedule-indexing.d.ts +2 -0
- package/dist/server/services/schedule-indexing.js +16 -0
- package/dist/server/services/virtual-collections-indexer.js +18 -5
- package/dist/server/services/virtual-collections-registry.js +2 -2
- package/package.json +1 -1
package/dist/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vegan-friendly/strapi-plugin-elasticsearch",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.9",
|
4
4
|
"description": "A Strapi plugin to enable using Elasticsearch with Strapi CMS.",
|
5
5
|
"homepage": "https://github.com/vegan-friendly/strapi-plugin-elasticsearch",
|
6
6
|
"strapi": {
|
@@ -14,7 +14,7 @@ exports.default = {
|
|
14
14
|
},
|
15
15
|
pluginOptions: {
|
16
16
|
'content-manager': {
|
17
|
-
visible:
|
17
|
+
visible: true,
|
18
18
|
},
|
19
19
|
'content-type-builder': {
|
20
20
|
visible: false,
|
@@ -23,14 +23,14 @@ exports.default = {
|
|
23
23
|
attributes: {
|
24
24
|
collection_name: {
|
25
25
|
type: 'string',
|
26
|
-
required:
|
26
|
+
required: false,
|
27
27
|
},
|
28
28
|
item_id: {
|
29
29
|
type: 'integer',
|
30
30
|
},
|
31
31
|
indexing_status: {
|
32
32
|
type: 'enumeration',
|
33
|
-
enum: ['to-be-done', 'done'],
|
33
|
+
enum: ['to-be-done', 'in-progress', 'done'],
|
34
34
|
required: true,
|
35
35
|
default: 'to-be-done',
|
36
36
|
},
|
package/dist/server/index.d.ts
CHANGED
@@ -143,6 +143,8 @@ declare const _default: {
|
|
143
143
|
}): Promise<void>;
|
144
144
|
getItemsPendingToBeIndexed(): Promise<any>;
|
145
145
|
markIndexingTaskComplete(recId: any): Promise<void>;
|
146
|
+
markIndexingTaskInProgress(recId: any): Promise<void>;
|
147
|
+
getFullIndexingInProgress(): Promise<any>;
|
146
148
|
};
|
147
149
|
esInterface: ({ strapi }: {
|
148
150
|
strapi: any;
|
@@ -150,8 +152,8 @@ declare const _default: {
|
|
150
152
|
indexer: ({ strapi }: {
|
151
153
|
strapi: any;
|
152
154
|
}) => {
|
153
|
-
rebuildIndex(): Promise<boolean>;
|
154
|
-
indexCollection(collectionName: any, indexName?: string | null): Promise<
|
155
|
+
rebuildIndex(item?: any): Promise<boolean>;
|
156
|
+
indexCollection(collectionName: any, indexName?: string | null): Promise<number>;
|
155
157
|
indexPendingData(): Promise<boolean>;
|
156
158
|
};
|
157
159
|
logIndexing: ({ strapi }: {
|
@@ -39,6 +39,8 @@ declare const _default: {
|
|
39
39
|
}): Promise<void>;
|
40
40
|
getItemsPendingToBeIndexed(): Promise<any>;
|
41
41
|
markIndexingTaskComplete(recId: any): Promise<void>;
|
42
|
+
markIndexingTaskInProgress(recId: any): Promise<void>;
|
43
|
+
getFullIndexingInProgress(): Promise<any>;
|
42
44
|
};
|
43
45
|
esInterface: ({ strapi }: {
|
44
46
|
strapi: any;
|
@@ -46,8 +48,8 @@ declare const _default: {
|
|
46
48
|
indexer: ({ strapi }: {
|
47
49
|
strapi: any;
|
48
50
|
}) => {
|
49
|
-
rebuildIndex(): Promise<boolean>;
|
50
|
-
indexCollection(collectionName: any, indexName?: string | null): Promise<
|
51
|
+
rebuildIndex(item?: any): Promise<boolean>;
|
52
|
+
indexCollection(collectionName: any, indexName?: string | null): Promise<number>;
|
51
53
|
indexPendingData(): Promise<boolean>;
|
52
54
|
};
|
53
55
|
logIndexing: ({ strapi }: {
|
@@ -1,8 +1,8 @@
|
|
1
1
|
declare const _default: ({ strapi }: {
|
2
2
|
strapi: any;
|
3
3
|
}) => {
|
4
|
-
rebuildIndex(): Promise<boolean>;
|
5
|
-
indexCollection(collectionName: any, indexName?: string | null): Promise<
|
4
|
+
rebuildIndex(item?: any): Promise<boolean>;
|
5
|
+
indexCollection(collectionName: any, indexName?: string | null): Promise<number>;
|
6
6
|
indexPendingData(): Promise<boolean>;
|
7
7
|
};
|
8
8
|
export default _default;
|
@@ -1,31 +1,52 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.default = ({ strapi }) => ({
|
4
|
-
async rebuildIndex() {
|
4
|
+
async rebuildIndex(item = null) {
|
5
5
|
const helper = strapi.plugins['elasticsearch'].services.helper;
|
6
6
|
const esInterface = strapi.plugins['elasticsearch'].services.esInterface;
|
7
7
|
const scheduleIndexingService = strapi.plugins['elasticsearch'].services.scheduleIndexing;
|
8
8
|
const configureIndexingService = strapi.plugins['elasticsearch'].services.configureIndexing;
|
9
9
|
const logIndexingService = strapi.plugins['elasticsearch'].services.logIndexing;
|
10
10
|
const virtualCollectionsIndexer = strapi.plugins['elasticsearch'].services['virtualCollectionsIndexer'];
|
11
|
+
const virtualCollectionsRegistry = strapi.plugins['elasticsearch'].services['virtualCollectionsRegistry'];
|
11
12
|
try {
|
12
13
|
console.log('strapi-plugin-elasticsearch : Request to rebuild the index received.');
|
14
|
+
const fullIndexingInProgress = await scheduleIndexingService.getFullIndexingInProgress();
|
15
|
+
if (fullIndexingInProgress.length > 0) {
|
16
|
+
const msg = `Indexing is already in progress - see tasks ${fullIndexingInProgress.map((t) => t.id)}. This request is ignored and marked as failed.`;
|
17
|
+
console.log('strapi-plugin-elasticsearch : ' + msg);
|
18
|
+
await logIndexingService.recordIndexingFail(msg);
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
const cols = await configureIndexingService.getCollectionsConfiguredForIndexing();
|
22
|
+
const needsNewIndex = cols.length > 0 || virtualCollectionsRegistry.getAll().some((vc) => vc.indexAlias == null);
|
13
23
|
const oldIndexName = await helper.getCurrentIndexName();
|
14
24
|
console.log('strapi-plugin-elasticsearch : Recording the previous index name : ', oldIndexName);
|
15
25
|
//Step 1 : Create a new index
|
16
|
-
|
17
|
-
|
18
|
-
|
26
|
+
let newIndexName;
|
27
|
+
if (needsNewIndex) {
|
28
|
+
newIndexName = await helper.getIncrementedIndexName();
|
29
|
+
await esInterface.createIndex(newIndexName);
|
30
|
+
console.log('strapi-plugin-elasticsearch : Created new index with name : ', newIndexName);
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
newIndexName = oldIndexName;
|
34
|
+
console.log('strapi-plugin-elasticsearch : No need to create new index, as there are no collections to re-index, and no virtual-collections that use the default index. sticking to current index:', newIndexName);
|
35
|
+
}
|
19
36
|
//Step 2 : Index all the stuff on this new index
|
20
37
|
console.log('strapi-plugin-elasticsearch : Starting to index all data into the new index.');
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
38
|
+
if (item == null) {
|
39
|
+
item = await scheduleIndexingService.addFullSiteIndexingTask();
|
40
|
+
}
|
41
|
+
if (item?.id) {
|
42
|
+
await scheduleIndexingService.markIndexingTaskInProgress(item.id);
|
43
|
+
let entitiesIndexed = 0;
|
44
|
+
for (let r = 0; r < cols.length; r++) {
|
45
|
+
entitiesIndexed += await this.indexCollection(cols[r], newIndexName);
|
46
|
+
}
|
26
47
|
// Indexing the virtual collections
|
27
|
-
console.log('strapi-plugin-elasticsearch : Starting to index virtual collections.');
|
28
|
-
const
|
48
|
+
console.log('strapi-plugin-elasticsearch : Starting to index virtual collections. task id : ', item.id);
|
49
|
+
const virtualEntriesIndexed = await virtualCollectionsIndexer.reindexAll(newIndexName);
|
29
50
|
await scheduleIndexingService.markIndexingTaskComplete(item.id);
|
30
51
|
console.log('strapi-plugin-elasticsearch : Indexing of data into the new index complete.');
|
31
52
|
//Step 4 : Move the alias to this new index
|
@@ -34,7 +55,7 @@ exports.default = ({ strapi }) => ({
|
|
34
55
|
console.log('strapi-plugin-elasticsearch : Deleting the previous indices');
|
35
56
|
//Step 5 : Delete the previous index
|
36
57
|
await helper.deleteOldIndices();
|
37
|
-
await logIndexingService.recordIndexingPass(
|
58
|
+
await logIndexingService.recordIndexingPass(`Re-index site-wide content completed successfully. ${entitiesIndexed} entries indexed. ${virtualEntriesIndexed} virtual entries indexed.`);
|
38
59
|
return true;
|
39
60
|
}
|
40
61
|
else {
|
@@ -48,6 +69,11 @@ exports.default = ({ strapi }) => ({
|
|
48
69
|
await logIndexingService.recordIndexingFail(err);
|
49
70
|
throw err;
|
50
71
|
}
|
72
|
+
finally {
|
73
|
+
if (item?.id) {
|
74
|
+
await scheduleIndexingService.markIndexingTaskComplete(item.id);
|
75
|
+
}
|
76
|
+
}
|
51
77
|
},
|
52
78
|
async indexCollection(collectionName, indexName = null) {
|
53
79
|
const helper = strapi.plugins['elasticsearch'].services.helper;
|
@@ -93,7 +119,7 @@ exports.default = ({ strapi }) => ({
|
|
93
119
|
await esInterface.indexDataToSpecificIndex({ itemId: indexItemId, itemData: dataToIndex }, indexName);
|
94
120
|
}
|
95
121
|
}
|
96
|
-
return
|
122
|
+
return entries.length ?? 0;
|
97
123
|
},
|
98
124
|
async indexPendingData() {
|
99
125
|
const scheduleIndexingService = strapi.plugins['elasticsearch'].services.scheduleIndexing;
|
@@ -103,17 +129,22 @@ exports.default = ({ strapi }) => ({
|
|
103
129
|
const helper = strapi.plugins['elasticsearch'].services.helper;
|
104
130
|
const indexAlias = await strapi.config.get('plugin.elasticsearch').indexAliasName;
|
105
131
|
const recs = await scheduleIndexingService.getItemsPendingToBeIndexed();
|
106
|
-
const
|
132
|
+
const fullSiteIndexTasks = recs.filter((r) => r.full_site_indexing === true);
|
133
|
+
const fullSiteIndexing = fullSiteIndexTasks.length > 0;
|
107
134
|
if (fullSiteIndexing) {
|
108
|
-
await this.rebuildIndex();
|
109
|
-
|
110
|
-
|
135
|
+
const success = await this.rebuildIndex(fullSiteIndexTasks[0]);
|
136
|
+
if (success) {
|
137
|
+
// Mark all pending tasks as complete, as they are implicitly covered by the full-site indexing.
|
138
|
+
for (let r = 0; r < recs.length; r++)
|
139
|
+
await scheduleIndexingService.markIndexingTaskComplete(recs[r].id);
|
140
|
+
}
|
111
141
|
}
|
112
142
|
else {
|
113
143
|
try {
|
114
144
|
for (let r = 0; r < recs.length; r++) {
|
115
145
|
const col = recs[r].collection_name;
|
116
146
|
if (configureIndexingService.isCollectionConfiguredToBeIndexed(col)) {
|
147
|
+
await scheduleIndexingService.markIndexingTaskInProgress(recs[r].id);
|
117
148
|
//Indexing the individual item
|
118
149
|
if (recs[r].item_id) {
|
119
150
|
if (recs[r].indexing_type !== 'remove-from-index') {
|
@@ -15,5 +15,7 @@ declare const _default: ({ strapi }: {
|
|
15
15
|
}): Promise<void>;
|
16
16
|
getItemsPendingToBeIndexed(): Promise<any>;
|
17
17
|
markIndexingTaskComplete(recId: any): Promise<void>;
|
18
|
+
markIndexingTaskInProgress(recId: any): Promise<void>;
|
19
|
+
getFullIndexingInProgress(): Promise<any>;
|
18
20
|
};
|
19
21
|
export default _default;
|
@@ -59,4 +59,20 @@ exports.default = ({ strapi }) => ({
|
|
59
59
|
},
|
60
60
|
});
|
61
61
|
},
|
62
|
+
async markIndexingTaskInProgress(recId) {
|
63
|
+
await strapi.entityService.update('plugin::elasticsearch.task', recId, {
|
64
|
+
data: {
|
65
|
+
indexing_status: 'in-progress',
|
66
|
+
},
|
67
|
+
});
|
68
|
+
},
|
69
|
+
async getFullIndexingInProgress() {
|
70
|
+
const entries = await strapi.entityService.findMany('plugin::elasticsearch.task', {
|
71
|
+
filters: {
|
72
|
+
indexing_status: 'in-progress',
|
73
|
+
full_site_indexing: true,
|
74
|
+
},
|
75
|
+
});
|
76
|
+
return entries;
|
77
|
+
},
|
62
78
|
});
|
@@ -60,9 +60,9 @@ exports.default = ({ strapi }) => {
|
|
60
60
|
const privateIndexAlias = collection.indexAlias;
|
61
61
|
const helper = getHelperService();
|
62
62
|
let timestamp = Date.now();
|
63
|
+
let indexName = '';
|
63
64
|
try {
|
64
65
|
const esInterface = getElasticsearchService();
|
65
|
-
let indexName;
|
66
66
|
if (privateIndexAlias) {
|
67
67
|
indexName = await helper.getIncrementedIndexName(privateIndexAlias);
|
68
68
|
await esInterface.createIndex(indexName, collection.mappings);
|
@@ -71,14 +71,26 @@ exports.default = ({ strapi }) => {
|
|
71
71
|
indexName = await helper.getCurrentIndexName();
|
72
72
|
}
|
73
73
|
let page = 0;
|
74
|
-
let
|
74
|
+
let prevPageData = [];
|
75
75
|
let totalIndexed = 0;
|
76
|
-
|
76
|
+
const pageLimit = 10000;
|
77
|
+
while (page <= pageLimit) {
|
77
78
|
const pageData = await collection.extractData(page);
|
79
|
+
strapi.log.debug(`Extracted ${pageData.length} items from ${collectionName} for page ${page}`);
|
78
80
|
if (!Array.isArray(pageData) || pageData.length === 0) {
|
79
|
-
hasMoreData = false;
|
80
81
|
break;
|
81
82
|
}
|
83
|
+
if (JSON.stringify(prevPageData) == JSON.stringify(pageData)) {
|
84
|
+
throw new Error(`Infinite loop detected at page ${page} while reindexing ${collectionName}. Stopping reindexing. Check this virtual-collection's extractData().
|
85
|
+
current page 1st item (id ${pageData[0]?.id}):
|
86
|
+
${JSON.stringify(pageData[0])}
|
87
|
+
prev page 1st item (id ${prevPageData[0]?.id}):
|
88
|
+
${JSON.stringify(prevPageData[0])}`);
|
89
|
+
}
|
90
|
+
if (page >= pageLimit) {
|
91
|
+
strapi.log.warn(`Page ${page} of ${collectionName} is greater than page-limit (${pageLimit}). stopping indexing this virtual-collection.`);
|
92
|
+
pageData.length = pageLimit;
|
93
|
+
}
|
82
94
|
const operations = [];
|
83
95
|
for (const itemData of pageData) {
|
84
96
|
const itemId = collection.getIndexItemId(itemData.id, collectionName);
|
@@ -88,6 +100,7 @@ exports.default = ({ strapi }) => {
|
|
88
100
|
await Promise.all(operations.map((op) => esInterface.indexDataToSpecificIndex(op, indexName)));
|
89
101
|
}
|
90
102
|
totalIndexed += pageData.length;
|
103
|
+
prevPageData = pageData;
|
91
104
|
page++;
|
92
105
|
}
|
93
106
|
strapi.log.info(`Reindexed ${totalIndexed} items for virtual collection: ${collectionName}. took ${(0, humanize_duration_1.default)(Date.now() - timestamp)}. now updating alias.`);
|
@@ -102,7 +115,7 @@ exports.default = ({ strapi }) => {
|
|
102
115
|
return totalIndexed;
|
103
116
|
}
|
104
117
|
catch (error) {
|
105
|
-
strapi.log.error(`Error reindexing ${collectionName}: ${error?.message} after ${(0, humanize_duration_1.default)(Date.now() - timestamp)}`);
|
118
|
+
strapi.log.error(`Error reindexing ${collectionName} to index ${indexName}: ${error?.message} after ${(0, humanize_duration_1.default)(Date.now() - timestamp)}`);
|
106
119
|
throw error;
|
107
120
|
}
|
108
121
|
},
|
@@ -50,7 +50,7 @@ const configSchema = yup.object({
|
|
50
50
|
alsoTriggerDelete: yup.boolean().default(false),
|
51
51
|
}))
|
52
52
|
.default([]),
|
53
|
-
mappings: yup.object().
|
53
|
+
mappings: yup.object().optional(),
|
54
54
|
});
|
55
55
|
/**
|
56
56
|
* Service to handle indexing of virtual collections
|
@@ -73,7 +73,7 @@ exports.default = ({ strapi }) => {
|
|
73
73
|
const virtualCollectionsFactories = strapi.plugin('elasticsearch').config('virtualCollections') || [];
|
74
74
|
config = virtualCollectionsFactories.map((factory) => {
|
75
75
|
let collectionConfig = factory(strapi);
|
76
|
-
collectionConfig = configSchema.validateSync(collectionConfig
|
76
|
+
collectionConfig = configSchema.validateSync(collectionConfig);
|
77
77
|
collectionConfig.getIndexItemId = collectionConfig.getIndexItemId || ((id) => helper.getIndexItemId({ collectionName: collectionConfig.collectionName, itemId: id }));
|
78
78
|
return { ...defaultConf, ...collectionConfig };
|
79
79
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vegan-friendly/strapi-plugin-elasticsearch",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.9",
|
4
4
|
"description": "A Strapi plugin to enable using Elasticsearch with Strapi CMS.",
|
5
5
|
"homepage": "https://github.com/vegan-friendly/strapi-plugin-elasticsearch",
|
6
6
|
"strapi": {
|