|
@@ -357,7 +357,7 @@ class DbCreator {
|
|
|
parseField(rec.series, seriesMap, seriesArr, authorIds, rec.id);
|
|
|
|
|
|
//названия
|
|
|
- parseField(rec.title, titleMap, titleArr, authorIds);
|
|
|
+ parseField(rec.title, titleMap, titleArr, authorIds, rec.id);
|
|
|
|
|
|
//жанры
|
|
|
let genre = rec.genre || emptyFieldValue;
|
|
@@ -533,7 +533,7 @@ class DbCreator {
|
|
|
|
|
|
//title
|
|
|
callback({job: 'title save', jobMessage: 'Сохранение индекса названий', jobStep: 8, progress: 0});
|
|
|
- await saveTable('title', titleArr, () => {titleArr = null}, true);
|
|
|
+ await saveTable('title', titleArr, () => {titleArr = null}, true, true);
|
|
|
|
|
|
//genre
|
|
|
callback({job: 'genre save', jobMessage: 'Сохранение индекса жанров', jobStep: 9, progress: 0});
|
|
@@ -557,7 +557,16 @@ class DbCreator {
|
|
|
});
|
|
|
|
|
|
callback({job: 'optimization', jobMessage: 'Оптимизация', jobStep: 11, progress: 0});
|
|
|
- await this.optimizeSeries(db, callback);
|
|
|
+ await this.optimizeSeries(db, (p) => {
|
|
|
+ if (p.progress)
|
|
|
+ p.progress = 0.5*p.progress;
|
|
|
+ callback(p);
|
|
|
+ });
|
|
|
+ await this.optimizeTitle(db, (p) => {
|
|
|
+ if (p.progress)
|
|
|
+ p.progress = 0.5*(1 + p.progress);
|
|
|
+ callback(p);
|
|
|
+ });
|
|
|
|
|
|
callback({job: 'stats count', jobMessage: 'Подсчет статистики', jobStep: 12, progress: 0});
|
|
|
await this.countStats(db, callback, stats);
|
|
@@ -672,6 +681,95 @@ class DbCreator {
|
|
|
await db.close({table: 'series'});
|
|
|
}
|
|
|
|
|
|
+ async optimizeTitle(db, callback) {
|
|
|
+ //оптимизация title, превращаем массив bookId в books, кладем все в title_book
|
|
|
+ await db.open({table: 'title'});
|
|
|
+
|
|
|
+ await db.create({
|
|
|
+ table: 'title_book',
|
|
|
+ flag: {name: 'toDel', check: 'r => r.toDel'},
|
|
|
+ });
|
|
|
+
|
|
|
+ const saveTitleChunk = async(titleChunk) => {
|
|
|
+ const ids = [];
|
|
|
+ for (const s of titleChunk) {
|
|
|
+ for (const id of s.bookId) {
|
|
|
+ ids.push(id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ids.sort((a, b) => a - b);// обязательно, иначе будет тормозить - особенности JembaDb
|
|
|
+
|
|
|
+ const rows = await db.select({table: 'book', where: `@@id(${db.esc(ids)})`});
|
|
|
+
|
|
|
+ const bookArr = new Map();
|
|
|
+ for (const row of rows)
|
|
|
+ bookArr.set(row.id, row);
|
|
|
+
|
|
|
+ for (const s of titleChunk) {
|
|
|
+ s.books = [];
|
|
|
+ s.bookCount = 0;
|
|
|
+ s.bookDelCount = 0;
|
|
|
+ for (const id of s.bookId) {
|
|
|
+ const rec = bookArr.get(id);
|
|
|
+ if (rec) {//на всякий случай
|
|
|
+ s.books.push(rec);
|
|
|
+ if (!rec.del)
|
|
|
+ s.bookCount++;
|
|
|
+ else
|
|
|
+ s.bookDelCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (s.books.length) {
|
|
|
+ s.series = s.books[0].series;
|
|
|
+ } else {
|
|
|
+ s.toDel = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ delete s.authorId;
|
|
|
+ delete s.bookId;
|
|
|
+ }
|
|
|
+
|
|
|
+ await db.insert({
|
|
|
+ table: 'title_book',
|
|
|
+ rows: titleChunk,
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const rows = await db.select({table: 'title'});
|
|
|
+
|
|
|
+ let idsLen = 0;
|
|
|
+ let chunk = [];
|
|
|
+ let processed = 0;
|
|
|
+ for (const row of rows) {// eslint-disable-line
|
|
|
+ chunk.push(row);
|
|
|
+ idsLen += row.bookId.length;
|
|
|
+ processed++;
|
|
|
+
|
|
|
+ if (idsLen > 20000) {//константа выяснена эмпирическим путем "память/скорость"
|
|
|
+ await saveTitleChunk(chunk);
|
|
|
+
|
|
|
+ idsLen = 0;
|
|
|
+ chunk = [];
|
|
|
+
|
|
|
+ callback({progress: processed/rows.length});
|
|
|
+
|
|
|
+ await utils.sleep(100);
|
|
|
+ utils.freeMemory();
|
|
|
+ await db.freeMemory();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (chunk.length) {
|
|
|
+ await saveTitleChunk(chunk);
|
|
|
+ chunk = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ await db.delete({table: 'title_book', where: `@@flag('toDel')`});
|
|
|
+ await db.close({table: 'title_book'});
|
|
|
+ await db.close({table: 'title'});
|
|
|
+ }
|
|
|
+
|
|
|
async countStats(db, callback, stats) {
|
|
|
//статистика по количеству файлов
|
|
|
|