<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Raspberry Pi Powered Vector Search | Bits And Music</title>
    <link>https://bitsandmusic.com/series/raspberry-pi-powered-vector-search/</link>
      <atom:link href="https://bitsandmusic.com/series/raspberry-pi-powered-vector-search/index.xml" rel="self" type="application/rss+xml" />
    <description>Raspberry Pi Powered Vector Search</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><lastBuildDate>Wed, 01 Jan 2025 00:00:00 +0000</lastBuildDate>
    <image>
      <url>https://bitsandmusic.com/images/icon_hua5672c1e15dce4d511903ad7fb945fd0_28771_512x512_fill_lanczos_center_2.png</url>
      <title>Raspberry Pi Powered Vector Search</title>
      <link>https://bitsandmusic.com/series/raspberry-pi-powered-vector-search/</link>
    </image>
    
    <item>
      <title>Playlist2vec: DIY Autoscaler For Docker Swarm - 2</title>
      <link>https://bitsandmusic.com/post/playlist2vec-docker-swarm-and-a-diy-autoscaler-2/</link>
      <pubDate>Wed, 01 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://bitsandmusic.com/post/playlist2vec-docker-swarm-and-a-diy-autoscaler-2/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer 1:&lt;/strong&gt; &lt;em&gt;This post continues the last post about building a playlist search and discovery application on a Raspberry Pi powered by the sequence-to-sequence model described in the post &amp;quot;Building Music Playlists Recommendation System.&amp;quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer 2:&lt;/strong&gt; &lt;em&gt;The design choices mentioned in this article are made keeping in mind a low-cost setup. As a result, some of the design choices may not be the most straightforward.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer 3:&lt;/strong&gt; &lt;em&gt;You can explore the vector search application, playlist2vec, here: &lt;a href=&#34;https://playlist2vec.com/&#34;&gt;https://playlist2vec.com/&lt;/a&gt;. You can find the code for the demo application &lt;a href=&#34;https://github.com/piyp791/playlist2vec&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&#34;brief-summary&#34;&gt;Brief Summary&lt;/h2&gt;

&lt;p&gt;In the initial setup for our vector search application, we had a &lt;a href=&#34;https://expressjs.com/&#34;&gt;NodeJS (Express JS)&lt;/a&gt; web server and &lt;a href=&#34;https://fastapi.tiangolo.com/&#34;&gt;FastAPI&lt;/a&gt; microservices for autocomplete and vector search features. All three are deployed as &lt;a href=&#34;https://www.docker.com/&#34;&gt;docker&lt;/a&gt; containers for ease of installation and scalability. We use the &lt;a href=&#34;https://github.com/unum-cloud/usearch&#34;&gt;USearch vector search&lt;/a&gt; library for vector search, and for autocomplete, we use a Python-based &lt;a href=&#34;https://en.wikipedia.org/wiki/Directed_acyclic_word_graph&#34;&gt;Directed Word Graph&lt;/a&gt; library called &lt;a href=&#34;https://github.com/seperman/fast-autocomplete&#34;&gt;fast-autocomplete&lt;/a&gt;. The entire setup is behind &lt;a href=&#34;https://nginx.org/en/&#34;&gt;Nginx&lt;/a&gt;, which acts as a reverse proxy for our setup.&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&#34;https://bitsandmusic.com/assets/images/playlist2vec.drawio.png&#34;  /&gt;
  &lt;figcaption&gt;
      &lt;p&gt;Playlist2vec design architecture. Scalable microservice-based architecture with NodeJS webserver, FastAPI-based vector search and autocomplete APIs, and Nginx as a reverse proxy.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;limitations&#34;&gt;Limitations&lt;/h2&gt;

&lt;p&gt;Despite support for these within our setup, there was no actual HTTPS or scaling implementation.
In this post, we will focus on adding scaling capability to our application using &lt;a href=&#34;https://docs.docker.com/engine/swarm/&#34;&gt;Docker Swarm&lt;/a&gt;.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;docker-swarm-from-containers-to-services&#34;&gt;Docker Swarm: From Containers To Services&lt;/h2&gt;

&lt;p&gt;Docker Swarm enables the deployment and management of multiple instances of applications, ensuring high availability and resilience.
The key distinction between deploying an application in swarm mode and using conventional Docker Compose lies in the added abstraction of &lt;a href=&#34;https://docs.docker.com/engine/swarm/services/&#34;&gt;services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Containers&lt;/strong&gt; are units of deployment which have their runtime. They encapsulate an application and its dependencies, including libraries, binaries, and configuration files, into a single, lightweight package. Each container runs in isolation from others, sharing the host operating system&#39;s kernel but maintaining its filesystem, processes, and network stack.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;strong&gt;services&lt;/strong&gt; represent a higher-level abstraction that defines how a specific application or a set of related applications should run in a container orchestration platform like Docker Swarm or &lt;a href=&#34;https://kubernetes.io/&#34;&gt;Kubernetes&lt;/a&gt;. A service specifies the desired state for a group of containers, including the number of replicas (instances) to run, the networking configuration, and the load-balancing strategy. When you create a service, the orchestration platform automatically manages the deployment and scaling of the underlying containers to meet the defined specifications.&lt;/p&gt;

&lt;h2 id=&#34;scaling-up-the-setup&#34;&gt;Scaling Up The Setup&lt;/h2&gt;

&lt;p&gt;Before transitioning to a Docker Swarm setup, we take the following steps to incorporate scaling into our configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add an additional Raspberry Pi to our machine cluster, ensuring that both machines can communicate with each other.&lt;/li&gt;
&lt;li&gt;Modify the vector search implementation to be memory-based, moving away from the previous &lt;a href=&#34;https://en.wikipedia.org/wiki/Mmap&#34;&gt;MMAP-based&lt;/a&gt;. This change allows us to better understand the resource requirements associated with scaling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;docker-swarm-config&#34;&gt;Docker Swarm Config&lt;/h2&gt;

&lt;p&gt;Here’s a snippet of the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file for one of the services, &lt;code&gt;autocomplete-service&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;autocomplete-service:
    build: ./autocomplete-service
    image: ${REGISTRY_HOST}:${REGISTRY_PORT}/autocomplete-image:latest
    networks:
      - p2v-network
    env_file:
      - .env
    deploy:
      replicas: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the &lt;a href=&#34;https://docs.docker.com/engine/swarm/stack-deploy/&#34;&gt;docker stack&lt;/a&gt; is deployed, this configuration scales the &lt;code&gt;autocomplete-service&lt;/code&gt; to run multiple instances (2 in this case). This setup enables the service to handle significantly more traffic compared to a single-instance configuration, enhancing its ability to manage increased load effectively.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;autoscaling&#34;&gt;Autoscaling&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Autoscaling&#34;&gt;Autoscaling&lt;/a&gt; is a cloud computing feature that automatically adjusts a service&#39;s number of active instances based on current demand. This ensures optimal resource utilization, maintains performance, and minimizes costs by dynamically scaling resources up or down in response to varying workloads.&lt;/p&gt;

&lt;p&gt;The core concept of an autoscaler is to define conditions that trigger scaling actions. Common criteria for scaling include CPU usage, memory consumption, or the number of requests indicative of traffic load.&lt;/p&gt;

&lt;p&gt;An autoscaler can operate in two primary ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Event-Driven Scaling:&lt;/strong&gt; Scaling actions are triggered by specific events, such as a sudden spike in traffic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Polling-Based Scaling:&lt;/strong&gt; A service continuously monitors a metric and initiates scaling actions when that metric crosses a defined threshold.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Docker Swarm does not natively support autoscaling capabilities, unlike Kubernetes, which offers robust &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/autoscaling/&#34;&gt;autoscaling features&lt;/a&gt;. However, it is possible to implement a basic autoscaling solution within an existing Docker Swarm setup.&lt;/p&gt;

&lt;h2 id=&#34;diy-autoscaling&#34;&gt;DIY Autoscaling&lt;/h2&gt;

&lt;p&gt;In this implementation, &lt;strong&gt;we focus on the number of requests within a specific timeframe as the primary condition for autoscaling.&lt;/strong&gt; We use Nginx&#39;s &lt;code&gt;access.log&lt;/code&gt; as our primary source of information for the requests logged.&lt;/p&gt;

&lt;p&gt;Our approach employs a polling mechanism with a 15-second interval. A bash script runs every 15 seconds to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve each endpoint&#39;s total number of requests within the last 15 seconds by using &lt;a href=&#34;https://en.wikipedia.org/wiki/AWK&#34;&gt;awk&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Determine the required number of replicas based on the request count based on our custom logic, implementing load-based scaling.&lt;/li&gt;
&lt;li&gt;Execute the &lt;code&gt;docker service scale&lt;/code&gt; command to adjust the number of replicas horizontally, effectively increasing or decreasing the number of service instances.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&#39;s a snippet of code as an example to get the total request count for an endpoint from the Nginx logs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;awk -v start=&amp;quot;$(date --date=&#39;15 seconds ago&#39; &#39;+%d/%b/%Y:%H:%M:%S&#39;)&amp;quot; \
    -v end=&amp;quot;$(date &#39;+%d/%b/%Y:%H:%M:%S&#39;)&amp;quot; \
    &#39;$4 &amp;gt;= &amp;quot;[&amp;quot;start&amp;quot;]&amp;quot; &amp;amp;&amp;amp; $4 &amp;lt;= &amp;quot;[&amp;quot;end&amp;quot;]&amp;quot; &amp;amp;&amp;amp; $7 ~ /\/populate/ {count++} \
    END {}&#39; /var/log/nginx.log
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To establish the relationship between the number of requests and the required replicas, we conduct load testing on our services using the load testing tool &lt;a href=&#34;https://k6.io/&#34;&gt;k6&lt;/a&gt;. By performing &lt;a href=&#34;https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/constant-arrival-rate/&#34;&gt;constant-rate arrival tests&lt;/a&gt;, we identify the maximum requests a single Docker instance can handle for each service on our specific hardware. This data informs our autoscaling setup, ensuring we can effectively manage resource allocation in response to varying traffic demands.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Autoscaling Pseudocode

// Read request counts from the Nginx access log for each endpoint
request_counts = read_log_parser_output()

// Determine the required number of service replicas based on 
// request counts based on our custom logic and prior load testing
required_service_replicas_lookup = get_scale(request_counts)

// Execute scaling commands for each service
FOR EACH service, replicas IN required_service_replicas_lookup:
    scale_service(service, replicas)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;thoughts&#34;&gt;Thoughts&lt;/h2&gt;

&lt;h3 id=&#34;the-good&#34;&gt;The Good&lt;/h3&gt;

&lt;h4 id=&#34;lowcost-setup-which-works&#34;&gt;Low-Cost Setup Which Works&lt;/h4&gt;

&lt;p&gt;This setup is Ideal for small to medium-scale projects due to its low resource requirements. It lacks the complexity of more advanced frameworks like Kubernetes, requires only Linux&#39;s awk and python installation and is simple enough to set up and deploy, making managing it easier.&lt;/p&gt;

&lt;h4 id=&#34;customizability&#34;&gt;Customizability&lt;/h4&gt;

&lt;p&gt;It offers greater control over the autoscaling logic, allowing for adjustments such as adding custom logic to monitor additional metrics, making the scaling logic more sophisticated or simply modifying the polling duration.&lt;/p&gt;

&lt;h3 id=&#34;the-bad&#34;&gt;The Bad&lt;/h3&gt;

&lt;h4 id=&#34;dependency-on-load-testing&#34;&gt;Dependency on Load Testing&lt;/h4&gt;

&lt;p&gt;Given that our scaling setup uses predefined load thresholds, the primary limitation of our DIY setup is its dependence upon manual load testing to determine appropriate scaling thresholds.&lt;/p&gt;

&lt;h4 id=&#34;polling-limitations&#34;&gt;Polling Limitations&lt;/h4&gt;

&lt;p&gt;Another limitation of our polling-based scaling setup is that it may miss traffic peaks since any decision on whether to scale or not can come only after a predefined duration of 15 seconds, leading to delayed scaling responses.&lt;/p&gt;

&lt;h4 id=&#34;clunky-setup&#34;&gt;Clunky Setup&lt;/h4&gt;

&lt;p&gt;Given that the setup involves setting up a cron job every 15 seconds, setting up the correct path to the nginx logs, the autoscale scripts, etc., it can feel quite clunky compared to industry-standard autoscaling frameworks such as Kubernetes.&lt;/p&gt;

&lt;h4 id=&#34;limited-metrics&#34;&gt;Limited Metrics&lt;/h4&gt;

&lt;p&gt;The setup only considers the number of incoming requests reading from nginx logs. It does not consider other vital metrics, such as CPU and memory usage, which would be valuable indicators when evaluating scaling needs. Libraries such as &lt;a href=&#34;https://github.com/google/cadvisor&#34;&gt;cAdvisor&lt;/a&gt;, which can get container health metrics such as CPU usage, memory, etc, can be added to this setup to get a complete picture before deciding to scale.&lt;/p&gt;

&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We added a simple (auto)scaling capability to our vector search application deployed on a cluster of Raspberry Pis. The setup is highly low-cost but has limitations, such as being prone to missing traffic peaks, requiring manual load testing before the setup, and having limited metrics under consideration for scaling. Adding a standardized auto scaler such as Kubernetes would be the next step.&lt;/p&gt;

&lt;p&gt;Until the next iteration.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Playlist2vec: A Raspberry-Pi Powered Vector Search System - 1</title>
      <link>https://bitsandmusic.com/post/playlist2vec-a-raspberry-pi-powered-vector-search-system-1/</link>
      <pubDate>Wed, 04 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://bitsandmusic.com/post/playlist2vec-a-raspberry-pi-powered-vector-search-system-1/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer 1:&lt;/strong&gt; &lt;em&gt;The design choices mentioned in this article are made keeping in mind a low-cost setup. As a result, some of the design choices may not be the most straightforward ones.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer 2:&lt;/strong&gt; &lt;em&gt;You can explore the vector search application, playlist2vec, here: &lt;a href=&#34;https://playlist2vec.com/&#34;&gt;https://playlist2vec.com/&lt;/a&gt;. You can find the code for the demo application &lt;a href=&#34;https://github.com/piyp791/playlist2vec&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In 2019, we published a &lt;a href=&#34;https://bitsandmusic.com/publication/playlist2vec/&#34;&gt;paper&lt;/a&gt; titled &amp;quot;Representation, Exploration, and Recommendation of Music Playlists.&amp;quot; In this work, we utilized &lt;a href=&#34;https://en.wikipedia.org/wiki/Seq2seq&#34;&gt;sequence-to-sequence models&lt;/a&gt; to create playlist &lt;a href=&#34;https://www.cloudflare.com/en-gb/learning/ai/what-are-embeddings/&#34;&gt;embeddings&lt;/a&gt;, which can be employed for various downstream tasks like search and discovery. You can see these embeddings in action at &lt;a href=&#34;https://playlist2vec.com/&#34;&gt;playlist2vec.com&lt;/a&gt;. The purpose of this post is to explain how we built Playlist2Vec, a playlist search application powered by the embeddings mentioned earlier.&lt;/p&gt;

&lt;h2 id=&#34;main-features&#34;&gt;Main Features&lt;/h2&gt;

&lt;p&gt;The main features of the app are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A search box with typeahead search where users can enter the item&#39;s name they are looking for.&lt;/li&gt;
&lt;li&gt;After selecting their preferred playlist name and submitting it, the system will display playlists similar to the one queried.&lt;/li&gt;
&lt;li&gt;The app provides &lt;a href=&#34;https://open.spotify.com/&#34;&gt;Spotify&lt;/a&gt; URLs for the items, allowing users to navigate to them from the results page easily.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;design-considerations&#34;&gt;Design Considerations&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The typeahead search must be instantaneous.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://www.ibm.com/topics/vector-search&#34;&gt;vector search&lt;/a&gt; should be capable of completing in under 2 seconds on a low-cost machine, like a &lt;a href=&#34;https://www.raspberrypi.com/&#34;&gt;Raspberry Pi&lt;/a&gt;, under normal traffic load.&lt;/li&gt;
&lt;li&gt;Both vector and full-text search should be deployable onto a single machine with 4GB of RAM.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;developer-friendly-outline&#34;&gt;Developer Friendly Outline&lt;/h2&gt;

&lt;p&gt;We primarily wanted a setup with a lower footprint but still scalable if needed. So, we designed our system using a &lt;a href=&#34;https://microservices.io/&#34;&gt;microservice architecture&lt;/a&gt; so that the system components are decoupled from each other and can be &lt;a href=&#34;https://wa.aws.amazon.com/wellarchitected/2020-07-02T19-33-23/wat.concept.horizontal-scaling.en.html&#34;&gt;horizontally scaled&lt;/a&gt; independently. With that in consideration, our tech stack looks like this for the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://expressjs.com/&#34;&gt;NodeJS (ExpressJS)&lt;/a&gt;&lt;/strong&gt; webserver&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://fastapi.tiangolo.com/&#34;&gt;FastAPI&lt;/a&gt;&lt;/strong&gt; for building two of our APIs; one is the search API for vector search, and the second is the autocomplete API for the typeahead search.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/unum-cloud/usearch&#34;&gt;USearch Vector Search Library&lt;/a&gt;&lt;/strong&gt; for vector search. Given a query playlist, similar playlists are found from a corpus of 745,543 playlists using vector search. This particular library was chosen because of its speed and &lt;a href=&#34;https://en.wikipedia.org/wiki/Mmap&#34;&gt;mmap&lt;/a&gt;* support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/seperman/fast-autocomplete&#34;&gt;Fast Autocomplete Python library&lt;/a&gt;&lt;/strong&gt;, a &lt;a href=&#34;https://en.wikipedia.org/wiki/Directed_acyclic_word_graph&#34;&gt;Directed Word Graph-based&lt;/a&gt; library for the typeahead search.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.sqlite.org/&#34;&gt;SQLite database&lt;/a&gt;&lt;/strong&gt; to store additional details for playlists such as Spotify ID, name, and cover image link. This specific database is for its portability and a smaller footprint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.docker.com/&#34;&gt;Docker&lt;/a&gt;&lt;/strong&gt; containers to run the APIs and the webserver to facilitate horizontal scaleup&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://nginx.org/en/&#34;&gt;Nginx, as a reverse proxy&lt;/a&gt;&lt;/strong&gt; for our setup, so that features such as caching, rate limiting, etc., do not have to be baked into the code. Configured to be installed on the host machine instead of running as a docker container**.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;overall-system-design&#34;&gt;Overall System Design&lt;/h2&gt;

&lt;p&gt;Here&#39;s how the workflow looks like:&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&#34;https://bitsandmusic.com/assets/images/playlist2vec.drawio.png&#34;  /&gt;
  &lt;figcaption&gt;
      &lt;p&gt;Playlist2vec design architecture. Scalable microservice-based architecture with NodeJS webserver, FastAPI-based vector search and autocomplete APIs, and Nginx as a reverse proxy.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol&gt;
&lt;li&gt;When you begin typing the item you want to search for, Nginx will return a cached response if one is available.&lt;/li&gt;
&lt;li&gt;If there is no cached response, the request is forwarded to the web server, which then sends it to the autocomplete API. The API returns a list of suggested item names and their corresponding IDs.&lt;/li&gt;
&lt;li&gt;Once the user selects an item from the list, the ID is sent to the web server, which forwards it to the search API. The USearch vector index retrieves the k-closest results.&lt;/li&gt;
&lt;li&gt;Additional details about these closest results, such as the playlist name, ID, and the cover image link, are then fetched from the SQLite database and returned to the browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;thoughts&#34;&gt;Thoughts&lt;/h2&gt;

&lt;h3 id=&#34;the-good&#34;&gt;The Good&lt;/h3&gt;

&lt;h4 id=&#34;scalable-architecture&#34;&gt;Scalable architecture&lt;/h4&gt;

&lt;p&gt;Using Docker containers to hold our system modules (web server, search, and autocomplete APIs) makes it easy to scale the setup if needed.&lt;/p&gt;

&lt;h4 id=&#34;memory-friendly-setup&#34;&gt;Memory friendly setup&lt;/h4&gt;

&lt;p&gt;We chose SQLite as our database and USearch as our vector search library due to their lower memory footprint and MMAP-based implementation. Since this system is read-only, we do not require the concurrency features offered by enterprise databases like MySQL or PostgreSQL. Regarding vector search, the mmap support allows us to avoid loading the vector search index into memory, which helps conserve system RAM. While the performance may not match memory-based alternatives, it is sufficient for our needs.&lt;/p&gt;

&lt;h4 id=&#34;robust-traffic-support-by-using-nginx&#34;&gt;Robust traffic support by using Nginx&lt;/h4&gt;

&lt;p&gt;Using Nginx enables robust support for traffic management, whether it is &lt;a href=&#34;https://blog.nginx.org/blog/rate-limiting-nginx&#34;&gt;rate limiting&lt;/a&gt; to prevent any DDOS attacks (or even any volume of traffic which are beyond what our application can handle), &lt;a href=&#34;https://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/&#34;&gt;caching&lt;/a&gt; (to have efficient utilization of system resources), or the rendering of static resources such as images, CSS, JS files, etc.&lt;/p&gt;

&lt;h3 id=&#34;the-bad&#34;&gt;The Bad&lt;/h3&gt;

&lt;h4 id=&#34;autocomplete-memory-consumption&#34;&gt;Autocomplete Memory Consumption&lt;/h4&gt;

&lt;p&gt;The memory consumption of the autocomplete API can be pretty high under heavy load. Considering mmap-based alternatives may be beneficial in this case.&lt;/p&gt;

&lt;h4 id=&#34;no-https-support&#34;&gt;No HTTPS support&lt;/h4&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/piyp791/playlist2vec/releases/tag/v1.0.0&#34;&gt;v1.0.0&lt;/a&gt; setup doesn&#39;t support HTTPS, so the setup requires something like a &lt;a href=&#34;https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/&#34;&gt;Cloudflare tunnel&lt;/a&gt; for HTTPS support.&lt;/p&gt;

&lt;p&gt;Additionally, there is no built-in HTTPS support for the search and autocomplete APIs. The Node.js web server communicates directly with the API containers without a proxy in place to manage SSL or other networking rules. This means that all traffic between the web server and the APIs is unencrypted.&lt;/p&gt;

&lt;h4 id=&#34;no-autoscaling-yet&#34;&gt;No (Auto)scaling (Yet)&lt;/h4&gt;

&lt;p&gt;Although the application has been designed to support scaling, the current version, v.1.0.0, still requires a scaling configuration, either &lt;a href=&#34;https://kubernetes.io/&#34;&gt;Kubernates&lt;/a&gt;-based or another approach.&lt;/p&gt;

&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We designed a playlist search application powered by the embeddings from the sequence-to-sequence model we described in our paper. The setup is low-cost, enabling it to be deployed on a Raspberry Pi while still being designed to be scalable if needed. This version does depend on an HTTPS frontend (such as a Cloudflare tunnel) and does not yet have any scaling configuration.&lt;/p&gt;

&lt;p&gt;Until the next iteration.&lt;/p&gt;

&lt;h2 id=&#34;notes&#34;&gt;Notes&lt;/h2&gt;

&lt;p&gt;*Memory-mapped I/O (mmap) is a technique that allows a file or a portion of a file to be directly mapped into the memory address space of a process. This enables applications to access the file&#39;s contents as though they were part of the program&#39;s memory, facilitating efficient file input/output (I/O) operations.&lt;/p&gt;

&lt;p&gt;**While Nginx could also have been installed as a docker container, we decided to run it on the host machine itself so as not to depend on the docker running itself, which can be used to show a maintenance page during any docker upgrades.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
