fix: tweak retention rate aggregation
This commit is contained in:
parent
42833cd921
commit
58fc17e3b6
5 changed files with 43 additions and 12 deletions
|
@ -40,6 +40,7 @@ You should also include the user name that made the change.
|
||||||
- fix(frontend): Safariでプラグインが複数ある場合に正常に読み込まれない問題を修正
|
- fix(frontend): Safariでプラグインが複数ある場合に正常に読み込まれない問題を修正
|
||||||
- Bookwyrmのユーザーのプロフィールページで「リモートで表示」をタップしても反応がない問題を修正
|
- Bookwyrmのユーザーのプロフィールページで「リモートで表示」をタップしても反応がない問題を修正
|
||||||
- `disableCache: true`を設定している場合に絵文字管理操作でエラーが出る問題を修正
|
- `disableCache: true`を設定している場合に絵文字管理操作でエラーが出る問題を修正
|
||||||
|
- リテンション分析が上手く機能しないことがあるのを修正
|
||||||
|
|
||||||
## 13.9.2 (2023/03/06)
|
## 13.9.2 (2023/03/06)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
export class retentionDateKey1678869617549 {
|
||||||
|
name = 'retentionDateKey1678869617549'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`TRUNCATE TABLE "retention_aggregation"`, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "retention_aggregation" ADD "dateKey" character varying(512) NOT NULL`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_f7c3576b37bd2eec966ae24477" ON "retention_aggregation" ("dateKey") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_f7c3576b37bd2eec966ae24477"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "retention_aggregation" DROP COLUMN "dateKey"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,12 @@ export class RetentionAggregation {
|
||||||
})
|
})
|
||||||
public updatedAt: Date;
|
public updatedAt: Date;
|
||||||
|
|
||||||
|
@Index({ unique: true })
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 512, nullable: false,
|
||||||
|
})
|
||||||
|
public dateKey: string;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
...id(),
|
...id(),
|
||||||
array: true,
|
array: true,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { bindThis } from '@/decorators.js';
|
||||||
import type { RetentionAggregationsRepository, UsersRepository } from '@/models/index.js';
|
import type { RetentionAggregationsRepository, UsersRepository } from '@/models/index.js';
|
||||||
import { deepClone } from '@/misc/clone.js';
|
import { deepClone } from '@/misc/clone.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type Bull from 'bull';
|
import type Bull from 'bull';
|
||||||
|
|
||||||
|
@ -49,13 +50,21 @@ export class AggregateRetentionProcessorService {
|
||||||
});
|
});
|
||||||
const targetUserIds = targetUsers.map(u => u.id);
|
const targetUserIds = targetUsers.map(u => u.id);
|
||||||
|
|
||||||
await this.retentionAggregationsRepository.insert({
|
try {
|
||||||
id: this.idService.genId(),
|
await this.retentionAggregationsRepository.insert({
|
||||||
createdAt: now,
|
id: this.idService.genId(),
|
||||||
updatedAt: now,
|
createdAt: now,
|
||||||
userIds: targetUserIds,
|
updatedAt: now,
|
||||||
usersCount: targetUserIds.length,
|
dateKey,
|
||||||
});
|
userIds: targetUserIds,
|
||||||
|
usersCount: targetUserIds.length,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (isDuplicateKeyValueError(err)) {
|
||||||
|
this.logger.succ('Skip because it has already been processed by another worker.');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 今日活動したユーザーを全て取得
|
// 今日活動したユーザーを全て取得
|
||||||
const activeUsers = await this.usersRepository.findBy({
|
const activeUsers = await this.usersRepository.findBy({
|
||||||
|
|
|
@ -36,9 +36,11 @@ async function renderChart() {
|
||||||
const wide = rootEl.offsetWidth > 600;
|
const wide = rootEl.offsetWidth > 600;
|
||||||
const narrow = rootEl.offsetWidth < 400;
|
const narrow = rootEl.offsetWidth < 400;
|
||||||
|
|
||||||
const maxDays = wide ? 15 : narrow ? 5 : 10;
|
const maxDays = wide ? 10 : narrow ? 5 : 7;
|
||||||
|
|
||||||
const raw = await os.api('retention', { });
|
let raw = await os.api('retention', { });
|
||||||
|
|
||||||
|
raw = raw.slice(0, maxDays);
|
||||||
|
|
||||||
const data = [];
|
const data = [];
|
||||||
for (const record of raw) {
|
for (const record of raw) {
|
||||||
|
@ -60,10 +62,9 @@ async function renderChart() {
|
||||||
const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300';
|
const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300';
|
||||||
|
|
||||||
// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする
|
// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする
|
||||||
//const max = raw.readWrite.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3;
|
const max = raw.map(x => x.users).slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3;
|
||||||
const max = 4;
|
|
||||||
|
|
||||||
const marginEachCell = 6;
|
const marginEachCell = 12;
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl, {
|
chartInstance = new Chart(chartEl, {
|
||||||
type: 'matrix',
|
type: 'matrix',
|
||||||
|
|
Loading…
Reference in a new issue