mirror of
https://github.com/badlogic/heissepreise.git
synced 2024-06-05 08:15:33 +02:00
patterns.js generates various pattern analysis results. Currently matches Billa products with Spar products and spits out some files to be imported as carts.
This commit is contained in:
parent
cb38e6c5c1
commit
d09bdc47e6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -14,3 +14,4 @@ tmp-dir/
|
||||||
site/data/latest-canonical*.json*
|
site/data/latest-canonical*.json*
|
||||||
site/output
|
site/output
|
||||||
copy
|
copy
|
||||||
|
patterns
|
||||||
|
|
62
patterns.js
Normal file
62
patterns.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const analysis = require("./analysis");
|
||||||
|
const knn = require("./site/js/knn");
|
||||||
|
|
||||||
|
if (!fs.existsSync("patterns")) fs.mkdirSync("patterns");
|
||||||
|
|
||||||
|
if (!fs.existsSync("patterns/sorted-billa-spar.json")) {
|
||||||
|
const items = analysis.readJSON("data/latest-canonical.json.br");
|
||||||
|
const billaSparItem = items
|
||||||
|
.filter((item) => item.store == "billa" || item.store == "spar")
|
||||||
|
.filter((item) => {
|
||||||
|
return !(
|
||||||
|
item.name.includes("Clever") ||
|
||||||
|
item.name.includes("S-BUDGET") ||
|
||||||
|
item.name.includes("Ja! Natürlich") ||
|
||||||
|
item.name.includes("SPAR") ||
|
||||||
|
item.name.includes("BILLA")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
knn.vectorizeItems(billaSparItem);
|
||||||
|
const billaItems = billaSparItem.filter((item) => item.store == "billa");
|
||||||
|
const sparItems = billaSparItem.filter((item) => item.store == "spar");
|
||||||
|
|
||||||
|
console.log(billaItems.length + " " + sparItems.length);
|
||||||
|
const sortedItems = [];
|
||||||
|
|
||||||
|
sparItems.forEach((item) => (item.sorted = false));
|
||||||
|
const total = billaItems.length;
|
||||||
|
while (billaItems.length > 0) {
|
||||||
|
const refItem = billaItems.shift();
|
||||||
|
const similar = knn.findMostSimilarItem(refItem, sparItems);
|
||||||
|
if (similar.item != null) {
|
||||||
|
sortedItems.push(refItem);
|
||||||
|
sortedItems.push(similar.item);
|
||||||
|
} else {
|
||||||
|
console.log("No similar item found for " + refItem.name);
|
||||||
|
}
|
||||||
|
if (sortedItems.length % 100 == 0) console.log(sortedItems.length / 2 + "/" + total);
|
||||||
|
}
|
||||||
|
analysis.writeJSON("patterns/sorted-billa-spar.json", sortedItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedItems = analysis.readJSON("patterns/sorted-billa-spar.json");
|
||||||
|
const filteredItems = [];
|
||||||
|
let result = "";
|
||||||
|
for (let i = 0; i < sortedItems.length; i += 2) {
|
||||||
|
const a = sortedItems[i];
|
||||||
|
const b = sortedItems[i + 1];
|
||||||
|
const similarity = knn.dotProduct(a.vector, b.vector);
|
||||||
|
result += "billa " + a.name + "\n";
|
||||||
|
result += "spar " + b.name + " " + similarity.toFixed(5) + "\n\n";
|
||||||
|
|
||||||
|
if (b.priceHistory.some((price) => price.price == a.price) && a.quantity == b.quantity) {
|
||||||
|
filteredItems.push(a);
|
||||||
|
filteredItems.push(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Sorted: " + sortedItems.length);
|
||||||
|
analysis.writeJSON("patterns/sorted-billa-spar-cart.json", { name: "Billa Spar Sortiert", items: sortedItems });
|
||||||
|
console.log("Filtered: " + filteredItems.length);
|
||||||
|
analysis.writeJSON("patterns/sorted-billa-spar-filtered-cart.json", { name: "Billa Spar Sortiert Gefiltert", items: filteredItems });
|
||||||
|
fs.writeFileSync("patterns/sorted-billa-spar.txt", result, "utf-8");
|
|
@ -133,7 +133,7 @@ function loadCart() {
|
||||||
});
|
});
|
||||||
cartList.elements.numItemsLabel.innerHTML = "<strong>Artikel:</strong>";
|
cartList.elements.numItemsLabel.innerHTML = "<strong>Artikel:</strong>";
|
||||||
cartList.elements.enableChart.checked = true;
|
cartList.elements.enableChart.checked = true;
|
||||||
cartList.elements.chart.elements.sumStores.checked = true;
|
cartList.elements.chart.elements.sumStores.checked = models.items.length < 2000;
|
||||||
|
|
||||||
if (cart.items.length == 0) {
|
if (cart.items.length == 0) {
|
||||||
elements.noItems.classList.remove("hidden");
|
elements.noItems.classList.remove("hidden");
|
||||||
|
|
|
@ -46,14 +46,19 @@ function findMostSimilarItem(refItem, items) {
|
||||||
let maxSimilarity = -1;
|
let maxSimilarity = -1;
|
||||||
let similarItem = null;
|
let similarItem = null;
|
||||||
let similarItemIdx = -1;
|
let similarItemIdx = -1;
|
||||||
items.forEach((item, idx) => {
|
for (let idx = 0; idx < items.length; idx++) {
|
||||||
|
const item = items[idx];
|
||||||
|
if (item.sorted) continue;
|
||||||
let similarity = dotProduct(refItem.vector, item.vector);
|
let similarity = dotProduct(refItem.vector, item.vector);
|
||||||
if (similarity > maxSimilarity) {
|
if (similarity > maxSimilarity || similarity > 0.9999999) {
|
||||||
maxSimilarity = similarity;
|
maxSimilarity = similarity;
|
||||||
similarItem = item;
|
similarItem = item;
|
||||||
similarItemIdx = idx;
|
similarItemIdx = idx;
|
||||||
}
|
}
|
||||||
});
|
if (similarity > 0.9999999) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
similarity: maxSimilarity,
|
similarity: maxSimilarity,
|
||||||
item: similarItem,
|
item: similarItem,
|
||||||
|
@ -96,16 +101,19 @@ function findMostSimilarItems(refItem, items, k = 5, accept = (ref, item) => tru
|
||||||
}
|
}
|
||||||
exports.findMostSimilarItems = findMostSimilarItems;
|
exports.findMostSimilarItems = findMostSimilarItems;
|
||||||
|
|
||||||
function similaritySortItems(items) {
|
function similaritySortItems(items, progress) {
|
||||||
if (items.length == 0) return items;
|
if (items.length == 0) return items;
|
||||||
sortedItems = [items.shift()];
|
sortedItems = [items.shift()];
|
||||||
let refItem = sortedItems[0];
|
let refItem = sortedItems[0];
|
||||||
while (items.length > 0) {
|
items.forEach((item) => (item.sorted = false));
|
||||||
|
while (items.length != sortedItems.length) {
|
||||||
const similarItem = findMostSimilarItem(refItem, items);
|
const similarItem = findMostSimilarItem(refItem, items);
|
||||||
sortedItems.push(similarItem.item);
|
sortedItems.push(similarItem.item);
|
||||||
items.splice(similarItem.index, 1);
|
similarItem.item.sorted = true;
|
||||||
refItem = similarItem.item;
|
refItem = similarItem.item;
|
||||||
|
if (progress) progress(sortedItems, items);
|
||||||
}
|
}
|
||||||
|
items.forEach((item) => delete item.sorted);
|
||||||
return sortedItems;
|
return sortedItems;
|
||||||
}
|
}
|
||||||
exports.similaritySortItems = similaritySortItems;
|
exports.similaritySortItems = similaritySortItems;
|
||||||
|
|
|
@ -36,7 +36,16 @@ class Carts extends Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
localStorage.setItem("carts", JSON.stringify(this._carts, null, 2));
|
const carts = [];
|
||||||
|
for (const cart of this._carts) {
|
||||||
|
carts.push({
|
||||||
|
name: cart.name,
|
||||||
|
items: cart.items.map((item) => {
|
||||||
|
return { store: item.store, id: item.id };
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
localStorage.setItem("carts", JSON.stringify(carts, null, 2));
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user