const express = require('express'); const bodyParser = require('body-parser'); const MTree = require('./m-tree/mtree'); const dimensions = 2; // Generator used to generate random points for the MTree const Generator = require('./data/generator'); // Express app const app = express(); app.use(bodyParser.json()); // Euclidean distance function used as the distance metric for the MTree function euclideanDistance(a, b) { return Math.sqrt(a.reduce((acc, val, i) => acc + (val - b[i]) ** 2, 0)); } // Create an MTree with the given dimensions and capacity, using the Euclidean distance const mtree = new MTree(dimensions, 10, euclideanDistance); // Generate 1000 random points const generator = new Generator(dimensions); const points = generator.generateMany(10000); // Insert all points into the MTree points.forEach(point => mtree.insert(point)); // Serve the index.html file app.get('/', (req, res) => { res.sendFile(__dirname + '/index.html'); }); // Return the MTree app.get('/tree', (req, res) => { res.send(JSON.parse(JSON.stringify(mtree, (key, value) => { if (key === 'parent' || key === 'mtree') return value && value.id; return value; }))); }); // Insert a point into the MTree app.post('/insert', (req, res) => { const point = req.body.point; if (!point || !Array.isArray(point)) { return res.status(400).send('Invalid point'); } mtree.insert(point); res.send('Point inserted'); }); // Perform a range query on the MTree app.get('/rangeQuery', (req, res) => { const { queryPoint, radius } = req.query; if (!queryPoint || !radius || JSON.parse(queryPoint).length !== dimensions) { return res.status(400).send('Invalid query parameters'); } console.time('mtreeRangeQuery'); const result = mtree.rangeQuery(JSON.parse(queryPoint), parseFloat(radius)); console.timeEnd('mtreeRangeQuery'); console.log(result); console.time('sequentialSearch'); const sequentialResult = points.filter(point => euclideanDistance(point, JSON.parse(queryPoint)) <= parseFloat(radius)); console.timeEnd('sequentialSearch'); //console.log(sequentialResult.map(point => "point:" + point +" distance: " + euclideanDistance(point, JSON.parse(queryPoint)))); console.log(sequentialResult); /*const furthestPoint = points.reduce((furthest, point) => { const distance = euclideanDistance(point, mtree.root.entries[0].point); return distance > euclideanDistance(furthest, mtree.root.entries[0].point) ? point : furthest; }, points[0]); console.log(`distance between first routing entry centroid and furthest point: ${euclideanDistance(furthestPoint, mtree.root.entries[0].point)}`); console.log(`radius of first routing entry: ${furthestPoint, mtree.root.entries[0].radius}`);*/ res.send(result); }); // Perform a k-NN query on the MTree app.get('/kNNQuery', (req, res) => { const { queryPoint, k } = req.query; if (!queryPoint || !k) { return res.status(400).send('Invalid query parameters'); } const parsedQueryPoint = JSON.parse(queryPoint); const kInt = parseInt(k, 10); console.time('mtreeSearch'); const result = mtree.kNNQuery(parsedQueryPoint, kInt); console.timeEnd('mtreeSearch'); console.time('sequentialSearch'); const sequentialResult = points.sort((a, b) => euclideanDistance(a, parsedQueryPoint) - euclideanDistance(b, parsedQueryPoint)).slice(0, kInt); console.timeEnd('sequentialSearch'); console.log(sequentialResult); res.send(result); }); // Start the server app.listen(3000, () => { console.log('MTree API is running on port 3000'); }); // Recreate the MTree with the given dimensions app.post('/recreate', (req, res) => { const { dimensions } = req.body; if (!dimensions || typeof dimensions !== 'number') { return res.status(400).send('Invalid dimensions'); } mtree = new MTree(dimensions, 10); points = generator.generateMany(100); points.forEach(point => mtree.insert(point)); res.send('MTree recreated'); });