Public
Edited
Nov 30, 2022
Insert cell
Insert cell
Insert cell
FederModule = import("https://unpkg.com/@zilliz/feder")
Insert cell
d3 = require("d3")
Insert cell
FederIndex = FederModule.FederIndex
Insert cell
filePath = "https://assets.zilliz.com/faiss_ivf_flat_voc_17k_ab112eec72.index"
Insert cell
sourceType = "faiss"
Insert cell
arrayBuffer = await fetch(filePath).then(res => res.arrayBuffer())
Insert cell
Insert cell
test_id = Math.ceil(Math.random() * 10000)
Insert cell
test_q = federIndex.getVectorById(test_id)
Insert cell
searchParams = {
return { nprobe: 6, k: 8 };
}
Insert cell
visitedRecords = federIndex.getSearchRecords(test_q, searchParams)
Insert cell
nodes = visitedRecords.fineSearchRecords.map(({ id, distance }) => ({
id,
distance
})).filter(node => node.distance > 0)
Insert cell
width = 800
Insert cell
height = 400
Insert cell
r = 3
Insert cell
x = d3.scaleLinear(d3.extent(nodes, node => node.distance), [0, width])
Insert cell
y = height / 2
Insert cell
Insert cell
Insert cell
svg(nodes)
Insert cell
svg = (nodes) => {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

nodes.forEach((node) => {
node._x = x(node.distance);
node._y = y;
node.x = x(node.distance);
node.y = node.type > 0 ? y : y / 2;
node.type = Math.floor(Math.random() * 3);
});
const colors = ["#66c2a5", "#fc8d62", "#8da0cb"];
const nodesCircle = svg
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("cx", (node) => node.x)
.attr("cy", (node) => node.y)
.attr("r", r)
.attr("fill", (node) => colors[node.type])
.attr("opacity", 0.5);

const simulation = d3
.forceSimulation(nodes)
.force(
"collision",
d3
.forceCollide()
.radius(r + 0.5)
.strength(1)
)
.force(
"y",
d3
.forceY()
.y((d) => d._y)
.strength((d) => 0.02 + 0.3 * d.type)
)
.force(
"x",
d3
.forceX()
.x((d) => d._x)
.strength(1)
)
.on("tick", () => {
nodes.forEach((node) => {
if (node.type <= 1) node.y = Math.min(node.y, y - 0.5 * r);
else node.y = Math.max(node.y, y + 0.5 * r);
});

nodesCircle.attr("cx", (d) => d.x);
nodesCircle.attr("cy", (d) => d.y);
})
.on("end", () => {
// const max_y =
// d3.min(
// nodes.filter((node) => node.type > 0),
// (node) => node.y
// ) -
// r * 3;
// nodes.forEach((node) => {
// if (node.type > 0) {
// // node.fx = node.x;
// // node.fy = node.y;
// } else {
// node.y = max_y
// }
// });
// d3.forceSimulation(nodes)
// .force(
// "collision",
// d3
// .forceCollide()
// .radius(r + 0.5)
// .strength(1)
// )
// .force(
// "y",
// d3
// .forceY()
// .y((d) => d._y)
// .strength((d) => 0.01 + d.type * 0.5)
// )
// .force(
// "x",
// d3
// .forceX()
// .x((d) => d._x)
// .strength(1)
// )
// .on("tick", () => {
// nodes.forEach((node) => {
// if (node.type <= 1) node.y = Math.min(node.y, y);
// else node.y = Math.max(node.y, y);
// });

// nodesCircle.attr("cx", (d) => d.x);
// nodesCircle.attr("cy", (d) => d.y);
// });
console.log(
nodes
.map((node) => Math.abs(node.x - node._x))
.reduce((acc, cur) => acc + cur) / nodes.length
);
});

return svg.node();
}
Insert cell
hnswFile = "https://assets.zilliz.com/hnswlib_hnsw_voc_17k_1f1dfd63a9.index"
Insert cell
hnswSource = 'hnswlib'
Insert cell
arrayBufferHnsw = fetch(hnswFile).then(res => res.arrayBuffer())
Insert cell
hnswFederIndex = new FederIndex(hnswSource, arrayBufferHnsw)
Insert cell
searchRecords = hnswFederIndex.getSearchRecords(test_q, { ef_search: 100, k: 8 })
Insert cell
nodesData_hnsw = {
const id2distance = {};
searchRecords.searchRecords.forEach((levelData) =>
levelData.forEach(([_, id, distance]) => {
if (distance > 0) id2distance[id] = distance;
})
);
return Object.entries(id2distance).map(([id, distance]) => ({
id,
distance
}));
}
Insert cell
svg(nodesData_hnsw)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more