Skip to content

Commit

Permalink
Merge pull request #33 from adobe/max-call-stack
Browse files Browse the repository at this point in the history
Guard against max call stack
  • Loading branch information
trieloff authored Dec 16, 2024
2 parents eb1dc6b + b94e899 commit e259483
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 34 deletions.
38 changes: 22 additions & 16 deletions distiller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
/* eslint-disable max-classes-per-file */
/*
* @module distiller
* This module is another service worker, which will handle the number crunching, i.e.
* filtering, aggregating, and summarizing the data.
*/
import { producer } from "./utils.js";
/* eslint-disable max-classes-per-file */
import { urlProducer } from './utils.js';
/**
* @typedef {Object} RawEvent - a raw RUM event
* @property {string} checkpoint - the name of the event that happened
Expand Down Expand Up @@ -105,11 +106,11 @@ class Aggregate {
}

get min() {
return Math.min(...this.values);
return this.values.reduce((min, val) => Math.min(min, val), Infinity);
}

get max() {
return Math.max(...this.values);
return this.values.reduce((max, val) => Math.max(max, val), -Infinity);
}

get share() {
Expand Down Expand Up @@ -393,16 +394,19 @@ export class DataChunks {
* @param {string} baseFacet name of the base facet, from which to derive the clusters
* @param {object} clusterOptions options
* @param {number} clusterOptions.count number of clusters, The default value is log10(nValues)
* @param {function} clusterOptions.producer function that takes the cluster value and returns all possible cluster values
* @param {function} clusterOptions.producer function that takes the cluster value and returns
* all possible cluster values
*/
addClusterFacet(facetName, baseFacet, { count: clustercount = Math.floor(Math.log10(this.facets[baseFacet].length)),
producer: urlProducer }) {
addClusterFacet(facetName, baseFacet, {
count: clustercount = Math.floor(Math.log10(this.facets[baseFacet].length)),
producer = urlProducer,
}) {
const facetValues = this.facets[baseFacet];

const createClusterMap = () => {
const clusterMap = facetValues.reduce((map, facet) => {
const clusters = producer(facet.value);
clusters.forEach(cluster => {
clusters.forEach((cluster) => {
if (!map.has(cluster)) {
map.set(cluster, 0);
}
Expand All @@ -412,24 +416,26 @@ export class DataChunks {
}, new Map());

// Find the most occurring cluster
const [mostOccurringCluster] = [...clusterMap.entries()].sort((a, b) => b[1] - a[1]).map(([cluster]) => cluster);
const [mostOccurringCluster] = [...clusterMap.entries()]
.sort((a, b) => b[1] - a[1])
.map(([cluster]) => cluster);

// Calculate the total number of items in the superset cluster
const totalItemsInSupersetCluster = Math.floor(facetValues.length + clustercount);

return { clusterMap, mostOccurringCluster, totalItemsInSupersetCluster };
};

const { clusterMap, mostOccurringCluster, totalItemsInSupersetCluster } = createClusterMap();
const { clusterMap } = createClusterMap();
const sortedClusters = [...clusterMap.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, clustercount)
.map(([cluster]) => cluster);
.sort((a, b) => b[1] - a[1])
.slice(0, clustercount)
.map(([cluster]) => cluster);

this.addFacet(facetName, (bundle) => {
const facetMatch = facetValues.find(f => f.entries.some(e => e.id === bundle.id));
const clusters = producer(facetMatch.value);
return [ facetMatch, ...clusters.filter(cluster => sortedClusters.includes(cluster)) ];
const facetMatch = facetValues.find((f) => f.entries.some((e) => e.id === bundle.id));
const clusters = producer(facetMatch.value);
return [facetMatch, ...clusters.filter((cluster) => sortedClusters.includes(cluster))];
});
}

Expand Down
2 changes: 1 addition & 1 deletion facets.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const facets = {
}
return u.toString();
}),
};
};

/**
* A facet function takes a bundle and returns an array of facet values.
Expand Down
15 changes: 9 additions & 6 deletions stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,15 @@ export function roundToConfidenceInterval(
// e.g. 3.14 and 3.16 have 2 significant digits in common
const maxStr = max.toPrecision(`${max}`.length);
const minStr = min.toPrecision(`${min}`.length);
const common = Math.min(maxStr.split('').reduce((acc, digit, i) => {
if (digit === minStr[i]) {
return acc + 1;
}
return acc;
}, 0), Number.isNaN(maxPrecision) ? Infinity : maxPrecision);
const common = Math.min(
maxStr.length > 0 ? [...maxStr].reduce((acc, digit, i) => {
if (digit === minStr[i]) {
return acc + 1;
}
return acc;
}, 0) : 0,
Number.isNaN(maxPrecision) ? Infinity : maxPrecision,
);
const precision = Math.max(
Math.min(2, Number.isNaN(maxPrecision) ? Infinity : maxPrecision),
common,
Expand Down
18 changes: 10 additions & 8 deletions test/distiller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ describe('DataChunks', () => {
assert.equal(totals.toptime.mean, 150);
assert.equal(totals.clickcount.sum, 1);
assert.equal(totals.clickcount.mean, 0.5);
assert.equal(totals.clickcount.min, 0);
assert.equal(totals.clickcount.max, 1);
});

it('DataChunk.aggregate()', () => {
Expand Down Expand Up @@ -822,7 +824,7 @@ describe('DataChunks', () => {
});

describe('DataChunks.hasConversion', () => {
const chunks = [
const testChunks = [
{
date: '2024-05-06',
rumBundles: [
Expand Down Expand Up @@ -887,7 +889,7 @@ describe('DataChunks.hasConversion', () => {

it('will tag bundles with convert and not-convert based on a filter spec', () => {
const d = new DataChunks();
d.load(chunks);
d.load(testChunks);

const spec = {
facetOne: ['top'],
Expand All @@ -906,7 +908,7 @@ describe('DataChunks.hasConversion', () => {

it('unknown facet in filter spec', () => {
const d = new DataChunks();
d.load(chunks);
d.load(testChunks);

const spec = {
facetOne: ['top'],
Expand Down Expand Up @@ -937,7 +939,7 @@ describe('DataChunks.addClusterFacet()', () => {

// Add a cluster facet based on the 'url' facet
d.addClusterFacet('urlCluster', 'url', {
count: Math.log10(d.facets.url.length),
count: Math.log10(d.facets.url.length),
});

const { facets } = d;
Expand All @@ -954,7 +956,7 @@ describe('DataChunks.addClusterFacet()', () => {

// Add a cluster facet based on the 'url' facet
d.addClusterFacet('urlCluster', 'url', {
count: Math.log10(d.facets.url.length),
count: Math.log10(d.facets.url.length),
});

const { facets } = d;
Expand All @@ -972,7 +974,7 @@ describe('DataChunks.addClusterFacet()', () => {
// Add a cluster facet based on the 'url' facet
const count = Math.floor(Math.log10(92));
d.addClusterFacet('urlCluster', 'url', {
count,
count,
});

// Check if the count is correct
Expand All @@ -988,7 +990,7 @@ describe('DataChunks.addClusterFacet()', () => {

// Add a cluster facet based on the 'url' facet
d.addClusterFacet('urlCluster', 'url', {
count: Math.log10(d.facets.url.length),
count: Math.log10(d.facets.url.length),
});

const { facets } = d;
Expand All @@ -997,4 +999,4 @@ describe('DataChunks.addClusterFacet()', () => {
const mostOccurringCluster = facets.urlCluster[0];
assert.ok(mostOccurringCluster.value, '/developer');
});
});
});
6 changes: 3 additions & 3 deletions utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export function addCalculatedProps(bundle) {
return bundle;
}

export function producer(url) {
export function urlProducer(url) {
const path = new URL(url).pathname;
return path
.split('/')
Expand All @@ -246,10 +246,10 @@ export function producer(url) {
...acc,
[
...acc.length ? [acc[acc.length - 1].split('/').slice(1)] : [],
part
part,
]
.flat()
.join('/')
.padStart(part.length + 1, '/')
.padStart(part.length + 1, '/'),
], []);
}

0 comments on commit e259483

Please sign in to comment.