<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nsukami</title>
    <description>The latest articles on DEV Community by Nsukami (@nsukami_).</description>
    <link>https://dev.to/nsukami_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3827933%2F5a0e396e-921f-4666-bcc1-fd28e3e109f4.jpg</url>
      <title>DEV Community: Nsukami</title>
      <link>https://dev.to/nsukami_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nsukami_"/>
    <language>en</language>
    <item>
      <title>Vectors</title>
      <dc:creator>Nsukami</dc:creator>
      <pubDate>Thu, 26 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/nsukami_/vectors-2l3a</link>
      <guid>https://dev.to/nsukami_/vectors-2l3a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fvectors.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fvectors.png" title="vectors" alt="vectors"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimers :
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Opinions&lt;/strong&gt; : The views expressed here are my own unless otherwise specified. They do not represent any employer, organization, or affiliated group.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code examples&lt;/strong&gt; : All code examples are educational. Production use requires careful consideration of performance, security, and your specific data characteristics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model choice&lt;/strong&gt; : The &lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt; model is a practical default, but embedding model selection should depend on your domain. Consider fine-tuning for specialized use cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;This article is for&lt;/strong&gt; : Django developers curious about semantic search and vector embeddings, or anyone wanting to understand how vectors fit alongside traditional structured data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;**This article was written on a Framework laptop 16, &lt;em&gt;yeah&lt;/em&gt;!  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Hook
&lt;/h2&gt;

&lt;p&gt;When I start a new Django project, the instinct is immediate and familiar: open &lt;code&gt;models.py&lt;/code&gt; and start writing classes. I think about my entity, its attributes, its relationships, and I translate that mental model almost directly into Python. That's great. It works. Since so many years. It's readable. It's what Django was built for. Amazing. Perfect. Flawless.&lt;/p&gt;

&lt;p&gt;If you follow my amazing and colossal work, you know that since more that two years now, I'm working on a project in the public health sector. I'm handling lots and lots and lots of data. I have to answer interesting questions like... Yet, I'm still reprensenting my data using classes and attributes. Reflexes.&lt;/p&gt;

&lt;p&gt;There's another way to represent data that's been quietly powering search engines, recommendation systems, and AI applications for years, it's increasingly accessible to application developers like me. I should learn to use it more often. Instead of describing data as a collection of named attributes, I can describe it as a &lt;strong&gt;point in a high-dimensional space&lt;/strong&gt; , a &lt;a href="https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics)" rel="noopener noreferrer"&gt;vector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through what that actually means, when it matters, and how to implement both approaches side by side in a real Django project. To increase your chances of understanding, it is recommended that you listen to this &lt;a href="https://www.youtube.com/watch?v=amBBO4PqJKo" rel="noopener noreferrer"&gt;track&lt;/a&gt; while reading the article. Enjoy!&lt;/p&gt;




&lt;h2&gt;
  
  
  ToC
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#classical-approach" rel="noopener noreferrer"&gt;The classical approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#vector-approach" rel="noopener noreferrer"&gt;The vector approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#why-not-ai" rel="noopener noreferrer"&gt;Why this is not just for AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#both-approaches" rel="noopener noreferrer"&gt;Both approaches in Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#going-further" rel="noopener noreferrer"&gt;Going further&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#broader-landscape" rel="noopener noreferrer"&gt;Representation models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/vctrs/#how-to-practice" rel="noopener noreferrer"&gt;How to practice&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The classical approach: data as structure
&lt;/h2&gt;

&lt;p&gt;When you model a medical facility in a &lt;a href="https://nskm.xyz/posts/syndromic-surveillance/" rel="noopener noreferrer"&gt;surveillance platform&lt;/a&gt;, you probably write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HealthFacility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;facility_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# hospital, clinic, health_post
&lt;/span&gt;    &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ManyToManyField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;structured representation&lt;/strong&gt;. Data lives in named slots. Querying it means matching those slots exactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Find clinics in Dakar with pediatric services
&lt;/span&gt;&lt;span class="n"&gt;HealthFacility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dakar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;facility_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clinic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;services__name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pediatrics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful for what it is. You know exactly what you're looking for, the schema enforces consistency, and &lt;a href="https://www.postgresql.org/docs/" rel="noopener noreferrer"&gt;SQL&lt;/a&gt; is extraordinarily good at these kinds of exact, predicate-based lookups.&lt;/p&gt;

&lt;p&gt;The limitation reveals itself the moment your questions become fuzzy. What if you want facilities that are &lt;em&gt;similar&lt;/em&gt; to a given one — without being able to define exactly what "similar" means? What if a user types "district hospital with maternal care near the coast" and you need to find the best match? Predicate-based filtering breaks down because similarity isn't a predicate. It's a geometry problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The vector approach: data as position
&lt;/h2&gt;

&lt;p&gt;A vector is simply an ordered list of numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0.82, 0.14, 0.67, 0.03, 0.91, ...]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is that you can encode the &lt;em&gt;meaning&lt;/em&gt; or &lt;em&gt;characteristics&lt;/em&gt; of any piece of data as a point in a high-dimensional space, such that &lt;strong&gt;things which are semantically similar end up close together&lt;/strong&gt; , and things that are different end up far apart.&lt;/p&gt;

&lt;p&gt;This is not hand-crafted feature engineering &lt;em&gt;(though it can be)&lt;/em&gt;. &lt;a href="https://huggingface.co/spaces/mteb/leaderboard" rel="noopener noreferrer"&gt;Modern embedding models&lt;/a&gt; — neural networks trained on massive datasets — can take a sentence, a document, even an image, and produce a dense vector that captures its semantic content. The model has learned, from context, what concepts relate to each other. "Maternal health clinic" and "obstetric care center" will produce vectors that are very close. "Warehouse" will be far away.&lt;/p&gt;

&lt;p&gt;The distance between two vectors is typically measured with &lt;a href="https://en.wikipedia.org/wiki/Cosine_similarity" rel="noopener noreferrer"&gt;cosine similarity&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;similarity = cos(θ) = (A · B) / (||A|| × ||B||)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A value of 1 means identical direction &lt;em&gt;(semantically equivalent)&lt;/em&gt;. A value of 0 means orthogonal &lt;em&gt;(unrelated)&lt;/em&gt;. This single number replaces the entire predicate matching logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this is not just for AI projects
&lt;/h2&gt;

&lt;p&gt;You might think: "I don't need semantic search. I need to store patient records." That's fair. This is exactly how I've done it on the &lt;a href="https://rh.pasteur.sn/en/research-and-public-health/epidemiology-clinical-research-and-data-science/fever-surveillance-syndromic-sentinel-surveillance-senegal-4s-network" rel="noopener noreferrer"&gt;4S project&lt;/a&gt;. But I'm more and more facing these new types of scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duplicate detection.&lt;/strong&gt; Two users register "Hôpital Principal de Dakar" and "hopital principal dakar". Exact matching fails. Vector similarity catches them as near-duplicates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation.&lt;/strong&gt;"Users who viewed this report also found these relevant." You don't need a collaborative filtering setup — you can just find the reports whose vectors are closest to the one currently being read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free-text search that actually works.&lt;/strong&gt; Users don't search with your field names. They type natural language. Vectors let you match that intent.... &lt;em&gt;This one stung me very badly recently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clustering without labels.&lt;/strong&gt; You have 10,000 epidemiological case reports. You want to discover natural groupings without writing filtering rules. Find neighborhoods in vector space.... We are working in this particular topic. I look at how we are implementing this feature and I am already disgusted by the direction we are taking. &lt;em&gt;Marvelous&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anomaly detection.&lt;/strong&gt; A new weekly report has a vector that is very far from all historical ones. Flag it for review.&lt;/p&gt;




&lt;h2&gt;
  
  
  Both approaches in Django: a concrete example
&lt;/h2&gt;

&lt;p&gt;Let's build a very small project that models epidemiological reports using both approaches. We'll use &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt;, a &lt;a href="https://www.postgresql.org/docs/current/extend.html" rel="noopener noreferrer"&gt;PostgreSQL extension&lt;/a&gt;, so vectors live right next to our traditional Django models. No separate &lt;a href="https://en.wikipedia.org/wiki/Vector_database" rel="noopener noreferrer"&gt;vector databases&lt;/a&gt;, no need for new infrastructure if you're already on the amazing &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;django pgvector sentence-transformers psycopg2-binary &lt;span class="c"&gt;# easy peasy&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable the extension in a Django migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pgvector.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VectorExtension&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migrations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;VectorExtension&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The traditional model
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# surveillance/models.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pgvector.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VectorField&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Classical structured representation.
    Every piece of information lives in a named, typed field.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;disease&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;week&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;case_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;severity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moderate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Moderate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;High&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# The vector representation lives alongside the structured one.
&lt;/span&gt;    &lt;span class="c1"&gt;# 384 dimensions is the output size of the model we'll use.
&lt;/span&gt;    &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VectorField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;384&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="c1"&gt;# Traditional index for structured queries
&lt;/span&gt;            &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disease&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;year&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, W&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;week&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that both representations coexist in the same table. This is intentional — we're not replacing one with the other. We're giving ourselves two different query interfaces into the same data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the embedding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# surveillance/embeddings.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;

&lt;span class="c1"&gt;# All-MiniLM-L6-v2 is small (80MB), fast, and produces 384-dim vectors.
# It runs on CPU without issue, which matters in resource-constrained environments.
# See here: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
&lt;/span&gt;
&lt;span class="n"&gt;_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_model&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_model&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_model&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SentenceTransformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_model&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;embed_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EpiReport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Convert a report&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s semantic content into a vector.
    The text we embed is a natural language description of the report,
    so the model can capture the meaning, not just the keywords.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Disease: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Region: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Severity: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The two query styles, side by side
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# surveillance/queries.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pgvector.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CosineDistance&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EpiReport&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.embeddings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_model&lt;/span&gt;

&lt;span class="c1"&gt;# ── Approach 1: Structured Query ────────────────────────────────────────────
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_high_severity_reports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Classical Django ORM query.
    Fast, precise, requires you to know exactly what you want.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-week&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ── Approach 2: Semantic Vector Query ───────────────────────────────────────
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_similar_reports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Vector similarity search.
    The query is natural language. No schema knowledge required.
    Returns the most semantically similar reports.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;query_vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;CosineDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_similar_to_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Given an existing report, find others that are semantically similar.
    Useful for &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;related reports&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; features or duplicate detection.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;CosineDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wiring it into views
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# surveillance/views.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JsonResponse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EpiReport&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.queries&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_high_severity_reports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;find_similar_reports&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;structured_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Traditional form-based search.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;reports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_high_severity_reports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disease&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;year&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;approach&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;structured&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disease&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;semantic_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Free-text semantic search.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_similar_reports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;approach&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vector&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disease&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;similarity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# convert distance to similarity
&lt;/span&gt;            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reports&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try these two requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /search/structured/?region=Dakar&amp;amp;disease=cholera&amp;amp;year=2024
GET /search/semantic/?q=waterborne disease outbreaks in coastal areas

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structured search finds exactly what you specified. The semantic search finds what you &lt;em&gt;meant&lt;/em&gt;, even if those exact words don't appear anywhere in your data. The world is beautiful.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to use which
&lt;/h2&gt;

&lt;p&gt;On top of my tiny experience, and as a software engineer who has never used this technique on &lt;em&gt;on production&lt;/em&gt;, I would say the right answer for most systems is both. And pgvector makes that even more practical without adding infrastructure complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lean on structured queries&lt;/strong&gt; when you need exactness: filtering by date range, counting cases, producing regulatory reports, joining across tables. SQL is unbeatable here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lean on vector queries&lt;/strong&gt; when you need semantic understanding: search boxes, recommendation engines, duplicate detection, anomaly flagging, clustering, or any time a user's intent can't be reduced to a dropdown value.&lt;/p&gt;

&lt;p&gt;Even more interesting, &lt;strong&gt;hybrid search&lt;/strong&gt; : use structured filters to narrow the candidate set, then rank the survivors by vector similarity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hybrid_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Filter structurally, then rank semantically.
    This is typically the most useful approach in production.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;query_vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;EpiReport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# hard filter: only this region
&lt;/span&gt;        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;CosineDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Going further
&lt;/h2&gt;

&lt;p&gt;Once you've internalized the two-lens model, here's where to take it next:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Fine-tune your own embedding model on domain data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt; &lt;a href="https://www.sbert.net/" rel="noopener noreferrer"&gt;model&lt;/a&gt; was trained on general English text. It has no idea that "paludisme" and "malaria" are the same thing, or that "cas suspects" and "suspected cases" are equivalent in my context. Training a domain-specific embedding model on my own epidemiological corpus — even with a small dataset using contrastive learning — would make similarity search dramatically more meaningful.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Retrieval-augmented generation (RAG) on top of our vector store
&lt;/h3&gt;

&lt;p&gt;Once we have a vector store of reports, we're one step away from a system that can &lt;em&gt;answer questions&lt;/em&gt; about your data in natural language. A user asks: &lt;em&gt;"What were the major respiratory disease trends in Guinea-Bissau in 2023?"&lt;/em&gt; — our system retrieves the most relevant reports by vector similarity, then feeds them as context to an &lt;a href="https://en.wikipedia.org/wiki/Large_language_model" rel="noopener noreferrer"&gt;LLM&lt;/a&gt; that synthesizes a coherent answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Vectors for anomaly detection in surveillance data
&lt;/h3&gt;

&lt;p&gt;Every week a new batch of case reports comes in. &lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#engineers" rel="noopener noreferrer"&gt;We&lt;/a&gt; can embed each report and compare it to the historical distribution of vectors for that region and disease. A report that lands far from the cluster is a statistical anomaly, potentially a real &lt;a href="https://www.who.int/activities/epidemic-and-pandemic-monitoring" rel="noopener noreferrer"&gt;outbreak signal&lt;/a&gt;. This turns our vector store into a passive early-warning system without writing any explicit outbreak-detection rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multimodal embeddings
&lt;/h3&gt;

&lt;p&gt;Text isn't the only thing we can embed. We can embed laboratory results, genomic sequences, geographic coordinates combined with case counts, even scanned paper forms via vision models. The moment we have multiple modalities in the same vector space, we can do cross-modal search: &lt;em&gt;find reports whose geographic spread pattern resembles this map image.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;placeholder image for brain explosion&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The theory underneath: why vector spaces work
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Representation models: other ways to represent data
&lt;/h2&gt;

&lt;p&gt;Structured attributes and vectors are two lenses. And there are other ways to represent data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Representation&lt;/th&gt;
&lt;th&gt;Best question it answers&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Class + attributes&lt;/td&gt;
&lt;td&gt;What does this thing have?&lt;/td&gt;
&lt;td&gt;Django ORM, PostgreSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector&lt;/td&gt;
&lt;td&gt;What is this thing like?&lt;/td&gt;
&lt;td&gt;pgvector, sentence-transformers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph&lt;/td&gt;
&lt;td&gt;How does this thing connect?&lt;/td&gt;
&lt;td&gt;Neo4j, networkx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event stream&lt;/td&gt;
&lt;td&gt;How did this thing become what it is?&lt;/td&gt;
&lt;td&gt;Kafka, EventStoreDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logic / facts&lt;/td&gt;
&lt;td&gt;What can we conclude about this thing?&lt;/td&gt;
&lt;td&gt;Prolog, Datalog, RDF/OWL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Probability&lt;/td&gt;
&lt;td&gt;How certain are we about this thing?&lt;/td&gt;
&lt;td&gt;PyMC, Stan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spatial&lt;/td&gt;
&lt;td&gt;Where is this thing, relative to what?&lt;/td&gt;
&lt;td&gt;PostGIS, GeoDjango&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tensor&lt;/td&gt;
&lt;td&gt;How does this vary across multiple dimensions?&lt;/td&gt;
&lt;td&gt;NumPy, PyTorch, Xarray&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to practice
&lt;/h2&gt;

&lt;p&gt;You don't need production data to start experimenting with vectors and embeddings:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local development:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.trychroma.com/" rel="noopener noreferrer"&gt;Chroma&lt;/a&gt;&lt;/strong&gt;: Lightweight vector database that runs locally or in Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://hub.docker.com/r/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector in Docker&lt;/a&gt;&lt;/strong&gt;: A local PostgreSQL with pgvector extension in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.sbert.net/docs/pretrained_models.html" rel="noopener noreferrer"&gt;Sentence Transformers Models&lt;/a&gt;&lt;/strong&gt;: Experiment with domain-specific models beyond all-MiniLM-L6-v2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learning resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://huggingface.co/models" rel="noopener noreferrer"&gt;Hugging Face Hub&lt;/a&gt;&lt;/strong&gt;: 100k+ pre-trained models. Read papers, compare benchmark results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://huggingface.co/learn" rel="noopener noreferrer"&gt;Embedding Models Course&lt;/a&gt;&lt;/strong&gt;: Free, practical introduction to embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector Documentation&lt;/a&gt;&lt;/strong&gt;: All indexing strategies and similarity operators explained.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  More on this topic
&lt;/h2&gt;

&lt;p&gt;As a Django engineer, my mental model of "data as class with attributes" is solid and won't stop serving &lt;a href="https://nskm.xyz/images/Nsukami_Patrick.pdf" rel="noopener noreferrer"&gt;me&lt;/a&gt;. But it's worth internalizing that it's one of at least two valid representations. I should definitely start to think of my data as having a &lt;em&gt;position&lt;/em&gt; in semantic space, a whole class of problems (search, similarity, anomaly, clustering) will become natural rather than bespoke.&lt;/p&gt;

&lt;p&gt;Here we are, we wanted a banana but we received a gorilla holding the banana and the entire jungle. Here are some links to help you &lt;em&gt;(and me, let's be honest)&lt;/em&gt; go further and tame the beast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/dev_kiran/embeddings-the-hidden-power-behind-ai-search-21eb"&gt;The hidden power behind AI &amp;amp; search&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.sbert.net/docs/training/overview.html" rel="noopener noreferrer"&gt;Fine-tuning sentence transformers&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://vickiboykis.com/what_are_embeddings/" rel="noopener noreferrer"&gt;Vector database comparison&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://lilianweng.github.io/posts/2021-05-31-contrastive/" rel="noopener noreferrer"&gt;Contrastive learning explained&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://arxiv.org/abs/2005.11401" rel="noopener noreferrer"&gt;Retrieval-Augmented Generation (RAG)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pgvector/pgvector#performance" rel="noopener noreferrer"&gt;pgvector performance tuning&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.cs.utexas.edu/~EWD/transcriptions/EWD06xx/EWD667.html" rel="noopener noreferrer"&gt;On the foolishness of "natural language programming"&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this article useful, &lt;em&gt;please like, share and subscribe&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  While I still have your attention
&lt;/h2&gt;

&lt;p&gt;The Norwegian Consumer Council is an independent, governmentally funded organisation that advocates for consumer’s rights. It should be easy for consumers to make sustainable choices every day. Consumers have the right to be protected against exploitation – both financially and digitally. To ensure this, we work to provide easy access to information, enforceable rights, and sufficient redress options when something goes wrong.&lt;/p&gt;

&lt;p&gt;Digital products and services keep getting worse. In the new report Breaking Free: Pathways to a fair technological future, the Norwegian Consumer Council has delved into &lt;a href="https://www.youtube.com/watch?v=T4Upf_B9RLQ" rel="noopener noreferrer"&gt;enshittification&lt;/a&gt; and how to resist it. The report shows how this phenomenon affects both consumers and society at large, but that it is possible to &lt;a href="https://www.forbrukerradet.no/breakingfree" rel="noopener noreferrer"&gt;turn the tide.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Geez&lt;/em&gt;, I would have loved to see African leaders do the same....&lt;/p&gt;

</description>
      <category>ai</category>
      <category>django</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>Syndromic Surveillance! (Part 1)</title>
      <dc:creator>Nsukami</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/nsukami_/syndromic-surveillance-part-1-1mn8</link>
      <guid>https://dev.to/nsukami_/syndromic-surveillance-part-1-1mn8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fsurveillance_screens.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fsurveillance_screens.jpg" title="Liberty" width="800" height="400"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimers :
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Opinions expressed in this post &lt;em&gt;(and in any of all my posts)&lt;/em&gt; are solely, &lt;em&gt;unless otherwise specified&lt;/em&gt;, those of the authors, &lt;em&gt;me&lt;/em&gt;. Those opinions absolutely do not reflect the views, policies, positions of any organizations, employers, affiliated groups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I've strived for accuracy throughout this piece, but if you catch any errors, please reach out—I'd be grateful for the feedback and happy to make updates!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TOC:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#hook" rel="noopener noreferrer"&gt;Hook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#history" rel="noopener noreferrer"&gt;Definition, context, history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#what" rel="noopener noreferrer"&gt;4S overview&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#core" rel="noopener noreferrer"&gt;Core principles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#collect" rel="noopener noreferrer"&gt;Data collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#process" rel="noopener noreferrer"&gt;Data processing and storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#share" rel="noopener noreferrer"&gt;Data sharing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#alert" rel="noopener noreferrer"&gt;Alerting and notifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#integration" rel="noopener noreferrer"&gt;Integration with existing systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#stack" rel="noopener noreferrer"&gt;The technological stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#front" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#back" rel="noopener noreferrer"&gt;Backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#else" rel="noopener noreferrer"&gt;More&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#engineers" rel="noopener noreferrer"&gt;The engineering team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#future" rel="noopener noreferrer"&gt;The roadmap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://nskm.xyz/posts/syndromic-surveillance/#more" rel="noopener noreferrer"&gt;More on this topic&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;Hook:&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;From &lt;strong&gt;June 30 to July 2, 2025&lt;/strong&gt; , a coordination meeting for the entire 4S network was recently held in &lt;a href="https://en.wikipedia.org/wiki/Lom%C3%A9" rel="noopener noreferrer"&gt;Lomé, Togo&lt;/a&gt;. During this meeting, a new implementation of the &lt;strong&gt;4S platform&lt;/strong&gt; was presented to the participants.&lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;p&gt;Quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Le réseau 4S a été conçu pour répondre à un besoin crucial, celui de disposer d'un système régional de surveillance capable de détecter précocément les maladies de santé publique, de renforcer les capacités de laboratoires et de partager des données pour une réponse adéquate et adaptée aux problèmes sanitaires.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quote :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The 4S network was designed to meet a crucial need: to have a regional surveillance system capable of early detection of public health diseases, strengthening laboratory capacities and sharing data for an adequate and appropriate response to health issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The striking disconnect that exists across many sectors, public health included. Officials excel at announcing initiatives and securing funding. Press releases about &lt;em&gt;"implementing advanced early detection systems"&lt;/em&gt; generate buzz and demonstrate progress. But when it comes to the unglamorous technical work: database design, API development, system integration... Silence. These crucial implementation details, handled by &lt;em&gt;anonymous engineers and developers&lt;/em&gt;, rarely see daylight in public discourse.&lt;/p&gt;

&lt;p&gt;While policy makers avoid technical specifics, it's precisely these software choices that determine whether systems function during critical moments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fmother.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fmother.jpg" title="Mother" alt="Mother" width="800" height="1065"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;Definition, context, history:&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;A syndromic surveillance system is a &lt;a href="https://www.youtube.com/watch?v=Y6DPDC_Mf90" rel="noopener noreferrer"&gt;public health&lt;/a&gt; &lt;strong&gt;surveillance&lt;/strong&gt; system that monitors &lt;strong&gt;symptom clusters&lt;/strong&gt; rather than specific confirmed diagnoses. It aims to &lt;strong&gt;detect epidemics or public health events&lt;/strong&gt; at an &lt;strong&gt;early&lt;/strong&gt; stage, by analyzing data in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  2007:
&lt;/h3&gt;

&lt;p&gt;Before 2007, &lt;a href="https://simple.wikipedia.org/wiki/Madagascar" rel="noopener noreferrer"&gt;Madagascar&lt;/a&gt; only had a passive, monthly paper-based reporting system that was _ &lt;strong&gt;too slow&lt;/strong&gt; _ for outbreak response. The &lt;em&gt;&lt;a href="https://pubmed.ncbi.nlm.nih.gov/17505252/" rel="noopener noreferrer"&gt;chikungunya outbreak&lt;/a&gt;&lt;/em&gt; in the Indian Ocean exposed _ &lt;strong&gt;critical gaps&lt;/strong&gt; _ in Madagascar's disease surveillance.&lt;/p&gt;

&lt;p&gt;The solution was to setup a real-time sentinel surveillance system using mobile phones for daily data transmission. This implementation was _ &lt;strong&gt;the first nationwide real-time-like&lt;/strong&gt; _ &lt;a href="https://pdfs.semanticscholar.org/66b8/8be85954b548c3b744ffd7ea8bac7ccae008.pdf" rel="noopener noreferrer"&gt;surveillance system&lt;/a&gt; ever established in Madagascar.&lt;/p&gt;

&lt;h3&gt;
  
  
  2012:
&lt;/h3&gt;

&lt;p&gt;The Syndromic Sentinel Surveillance System in Senegal, the 4S network, is &lt;a href="https://rh.pasteur.sn/en/research-and-public-health/epidemiology-clinical-research-and-data-science/fever-surveillance-syndromic-sentinel-surveillance-senegal-4s-network" rel="noopener noreferrer"&gt;Another syndromic sentinel surveillance system&lt;/a&gt; based on febrile syndromes. It was implemented in Senegal in 2012 and inpired by the Madagascar model.&lt;/p&gt;

&lt;p&gt;The criteria of individual target diseases are based on &lt;a href="https://www.who.int/publications/i/item/who-recommended-surveillance-standards" rel="noopener noreferrer"&gt;World Health Organization recommended surveillance standards&lt;/a&gt;. This means: for &lt;em&gt;each disease&lt;/em&gt; or &lt;em&gt;syndrome&lt;/em&gt; there is a description of the &lt;em&gt;rationale for surveillance, case definition, types of surveillance, minimum data elements, data analyses and principal uses of data for decision-making.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Data are transmitted on a daily basis by the general practitioners of the sentinel sites. They are validated and analyzed daily within the epidemiology unit of the Institution. These data are sent to the Ministry of Health in the form of a weekly newsletter.&lt;/p&gt;

&lt;h3&gt;
  
  
  2015:
&lt;/h3&gt;

&lt;p&gt;The existing implementation faced significant challenges. The database consisted of scattered Excel files distributed across multiple locations, making studies and analyses complicated and time-consuming. There was an urgent need to organize, structure, and centralize these disparate files.&lt;/p&gt;

&lt;p&gt;To address these issues, a new platform was developed: Teranga. Built using &lt;a href="https://httpd.apache.org/" rel="noopener noreferrer"&gt;Apache&lt;/a&gt;, &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;PHP&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="noopener noreferrer"&gt;Javascript&lt;/a&gt; and &lt;a href="https://www.mysql.com/products/community/" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;, Teranga provides improved data management, enhanced tracking capabilities, modular architecture, and streamlined deployment during outbreak situations.&lt;/p&gt;

&lt;p&gt;The new sentinel surveillance system included 17 health centers and &lt;a href="https://www.omicsonline.org/proceedings/early-outbreak-detection-through-sentinel-surveillance-system-in-senegal-51640.html" rel="noopener noreferrer"&gt;identified 4 confirmed outbreaks&lt;/a&gt;. The system has proved the feasibility of improving disease surveillance capacity through innovative technological solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  2020:
&lt;/h3&gt;

&lt;p&gt;When &lt;a href="https://www.cdc.gov/covid/about/index.html" rel="noopener noreferrer"&gt;COVID-19&lt;/a&gt; struck, Teranga rose to meet an unprecedented challenge, becoming the backbone of Senegal's pandemic response. Seamlessly coordinating patient care, traveler monitoring, financial operations, clinical research, and treatment center management across the entire country. The pandemic trully elevated Teranga to a mission-critical status.&lt;/p&gt;

&lt;h3&gt;
  
  
  2022:
&lt;/h3&gt;

&lt;p&gt;What began as a surveillance system for on institution, evolved to become West Africa indispensable healthcare hub: The 4S network. Teranga is now expanding from Senegal into other West African countries: Gambia, Cape-Verde, Mauritania, Niger, Mali, Togo, Guinea, Guinea Bissau, Sierra-Leone and Benin. The goal being to provide broader coverage and improve health systems in a sustainable and effective manner.&lt;/p&gt;

&lt;h3&gt;
  
  
  2023:
&lt;/h3&gt;

&lt;p&gt;I am hired by the Institution. I'm tasked with reimplementing the current system, rebuilding it from scratch while improving on what came before. I don't have much say in the tech stack, just enough &lt;em&gt;freedom&lt;/em&gt; to go with what works for &lt;a href="https://nskm.xyz/toolbelt/" rel="noopener noreferrer"&gt;me&lt;/a&gt;. The usual lineup of &lt;a href="https://www.debian.org/" rel="noopener noreferrer"&gt;Debian&lt;/a&gt;, &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://djangoproject.com/" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgresql&lt;/a&gt;, &lt;a href="https://www.nginx.org/" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt;, &lt;a href="https://podman.io" rel="noopener noreferrer"&gt;Podman&lt;/a&gt;, &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt;, &lt;a href="https://gitlab.com/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt;, &lt;a href="https://www.gnu.org/software/emacs/" rel="noopener noreferrer"&gt;Emacs&lt;/a&gt;, &lt;a href="https://tmuxcheatsheet.com/" rel="noopener noreferrer"&gt;Tmux&lt;/a&gt;, etc ... More on that in the following episodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2025:
&lt;/h3&gt;

&lt;p&gt;The surveillance platform my colleagues and I have spent two years developing has now been presented to the public. But public recognition &lt;a href="https://c.tenor.com/vLK4Mq3jiKIAAAAC/tenor.gif" rel="noopener noreferrer"&gt;is not really the source of my pride&lt;/a&gt;. What matters is that our system, our algorithms, our data structures, our functions, our for loops, our SQL queries are actively making a difference in saving lives. Phew!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fwip.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fwip.jpg" title="Work in progress..." alt="Work in progress" width="800" height="1065"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;4S overview:&lt;/u&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;identify unusual health events earlier and provide a quicker response.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I can't say it better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core principles:
&lt;/h3&gt;

&lt;p&gt;It's really fascinating that these early systems already recognized the core principles we are trying to implement today:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Standardized data collection:
&lt;/h4&gt;

&lt;p&gt;Healthcare providers at sentinel sites should use standardized digital forms to capture essential demographic, clinical, and temporal information. We want to ensure consistency across all participating facilities and enable accurate epidemiological analysis. We should always try to adhere to WHO surveillance standards with clearly predefined entities &amp;amp; attributes.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Data processing and storage:
&lt;/h4&gt;

&lt;p&gt;The platform should handles real-time data streaming between microservices, enabling immediate processing of incoming surveillance data. Each microservice should ensures data integrity through automated validation rules. We should always check for completeness, consistency, and quality. Validated data should be stored in a database with proper indexing for efficient retrieval.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Information sharing:
&lt;/h4&gt;

&lt;p&gt;The epidemiology unit generates documents consolidating validated surveillance data for the Ministry of Health. The platform integrates with third parties to share aggregated data with the Ministry of Health. The platform also provides interactive dashboards for stakeholders.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Alerting and notifications:
&lt;/h4&gt;

&lt;p&gt;The platform should ensure immediate notification delivery to relevant actor via email and dashboard notifications. Whenever needed, the platform should automatically generates notifications through multiple channels—email alerts, in-app notifications, and dashboard warnings.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Integration with existing systems:
&lt;/h4&gt;

&lt;p&gt;The platform should seamlessly integrate with the regional health data aggregation system and any other existing platform used by Ministry of Health. The system must also integrate easily with any biobank systems that may exist.&lt;/p&gt;

&lt;p&gt;A drawing is worth more than thousand words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                         [Health facility]   [Hospital]         [Clinic]
                                               |                 |                  |
                                               |                 |                  |
                                          +----+-----------------+------------------+----+
                                          |              4S platform                     |
                                          | • Data collection (Patients, symptoms, ...)  |
                                          | • Data validation &amp;amp; storage                  |
                                          | • Data treatment (Analyses, studies, ...)    |
                                          | • Data sharing (Reports, alerts, ...)        |
                                          | • Data dashboards (Statistics, plots, ...)   |
                                          +----+-------------------+-------------+-------+
                                               |                   |             |
                                          +----+----+              |        +----+----+
                                          | Reports |              |        | Alerts  |
                                          |Analytics|              |        |Warnings |
                                          +----+----+              |        +----+----+
                                               |                   |             |
                                               |                   |             |
                                         +-----+---------+   +-----+----+    +---+-------+
                                         | Public Health |   | Research |    | Emergency |
                                         |   Department  |   |          |    | Response  |
                                         +---------------+   +----------+    +-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the platform we are trying to build :) I can stop the post here, thanks for reading ...&lt;/p&gt;

&lt;h3&gt;
  
  
  The technological stack:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Frontend:
&lt;/h4&gt;

&lt;p&gt;The 4S platform frontend leverages &lt;a href="https://angularjs.dev/" rel="noopener noreferrer"&gt;AngularJS&lt;/a&gt; with &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, providing a dynamic and type-safe user interface that ensures smooth interactions for healthcare providers.&lt;/p&gt;

&lt;p&gt;One of the main component of our architecture is &lt;a href="https://www.keycloak.org/" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt;, an identity &amp;amp; access management solution that handles user authentication, authorization accross the entire platform. Customizing the Django Rest Framework's authentication classes to handle different tokens sent by different realms was an adventure worthy of an article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Backend:
&lt;/h4&gt;

&lt;p&gt;The backend infrastructure centers around &lt;a href="https://python.org" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://djangoproject.com" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, and Django Rest Framework. With each passing day, as we make progress on the project, I become more and more convinced that it was the right choice. Django is an amazing piece of software, thanks a lot to all its contributors.&lt;/p&gt;

&lt;p&gt;Data management is handled by &lt;a href="https://www.postgresql.org" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;, our primary database system. I can proudly say that I'm the one who made this choice. Postgresql is known for its reliability, strong adherence to SQL standards, powerful extensibility, support for complex data types, ACID compliance, robust security features, and excellent community support.&lt;/p&gt;

&lt;p&gt;To handle real-time communication and event-driven processes such as email notifications, lab result updates, and system alerts, we've integrated &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt;. Kafka ensures that critical healthcare information flows efficiently between different system components without data loss.&lt;/p&gt;

&lt;p&gt;In order to detect outbreaks, samples (blood, urine, stool, etc.) must be collected. And to effectively manage vast biological sample collections, ensure data integrity, and streamline complex workflows, we need a Biobank and a Biobanking software. A biobank is essentially an organized library of biological samples (like blood and tissue) that are stored alongside health and personal information, all used to support medical research. &lt;a href="https://www.modul-bio.com/en/our-solutions/mbiolims/" rel="noopener noreferrer"&gt;Mbiolims&lt;/a&gt; is the biobanking software we use to manage our samples and their associated data.&lt;/p&gt;

&lt;p&gt;Here too, I would need to write a really long article telling you how we've managed to do the integration between Django and MBioLIMS :) Hehe!&lt;/p&gt;

&lt;h4&gt;
  
  
  Operations:
&lt;/h4&gt;

&lt;p&gt;All code versioning and collaboration is managed through &lt;a href="https://git-scm.com" rel="noopener noreferrer"&gt;Git&lt;/a&gt; &amp;amp; Bitbucket, ensuring secure source code management, proper access controls and audit trails. While Bitbucket provides comprehensive version control and collaboration features, I'm still convinced it was not the right choice. &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt; ? &lt;a href="https://about.gitea.com/" rel="noopener noreferrer"&gt;Gitea&lt;/a&gt; ? Github ? Come on!&lt;/p&gt;

&lt;p&gt;The 4S platform is in fact a constallation of multiple running containers. Those containers are built using Docker and &lt;a href="https://podman.io" rel="noopener noreferrer"&gt;Podman&lt;/a&gt; technologies, enabling consistent deployment across different environments while simplifying development and testing workflows. I mean, I'm the only one using Podman while all my teammates are still using Docker :\&lt;/p&gt;

&lt;p&gt;Our continuous integration and deployment pipeline is powered by Jenkins. Jenkins automates testing and deployment processes to maintain code quality and enable rapid, reliable updates. I prefer &lt;a href="https://docs.gitlab.com/ci/" rel="noopener noreferrer"&gt;GitlabCI&lt;/a&gt; by 13 parsecs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; is used for container orchestration, deployment and operations. K8s provides automatic scaling, load balancing, and high availability to ensure our platform can handle varying loads and maintain uptime. My opinions on this tool are mixed.&lt;/p&gt;

&lt;p&gt;In one side, K8s will allow us to easily scale our applications up or down based on demand. This is a critical requirement for managing sensitive healthcare information. In the other side, I live in a part of the world where most medical facilities (most people, let's be honest) do not even have a working domain name, website, and email address. How can we ask them for the DevOps expertise to manage a Kubernetes cluster? I will see to what extent I can write an article about Kubernetes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Even more:
&lt;/h4&gt;

&lt;p&gt;There are other essential components of the system which I am not really familiar with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dhis2.org/" rel="noopener noreferrer"&gt;DHIS2&lt;/a&gt; is widely adopted across West Africa for integrated health information systems, disease surveillance, education management, and public health emergency response. We simply cannot ask a country that already uses DHIS2 to use the 4S platform without it being able to transfer data back to a DHIS2 instance.&lt;/p&gt;

&lt;p&gt;We have an &lt;a href="https://superset.apache.org/" rel="noopener noreferrer"&gt;Apache Superset&lt;/a&gt; instance for data visualization and exploration. With Apache Superset, we can easily let a third party consult some information, without modifying our system.&lt;/p&gt;

&lt;p&gt;Our platform generate lots of files, analysis reports &amp;amp; statistics. We needed something to store vast amounts of unstructured data, like images, videos, pdf documents, etc... We choosed &lt;a href="https://github.com/minio/minio" rel="noopener noreferrer"&gt;MinIO&lt;/a&gt; for this use case.&lt;/p&gt;

&lt;p&gt;The diagram we've seen above can also be seen using this different perspective:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    +-----------------------------------------------------------------------------------------------------------------------+
     |                                                      KUBERNETES CLUSTER                                               |
     +-----------------------------------------------------------------------------------------------------------------------+
     |                                                                                                                       |
     |  +--------------------------------------------------+   &amp;lt;-- (Auth/Roles) --&amp;gt;  +------------------+                    |
     |  |             FRONTEND CLIENTS                     |------------------------&amp;gt;|     KEYCLOAK     |                    |
     |  |          (AngularJS + TypeScript)                |&amp;lt;------------------------|   (Auth Server   |                    |
     |  +------------------^-------------------------------+                         +-----^------------+                    |
     |                     |                                                               |                                 |
     |              (API Requests)                                                         | (Auth/Roles)                    |
     |                     |                                                          +----+                                 |
     |                     |                                                          |                                      |
     +---------------------v----------------------------------------------------------v--------------------------------------+
     |  +--------------------------------------------------------------------------------+      +--------------------------+ |
     |  |                BACKEND MICROSERVICES (Django Rest Framework)                   |      |    Biobank (Mbiolims)    | |
     |  |      Microservices exchanges data via a message broker (Kafka in our case)     |&amp;lt;----&amp;gt;|   Stores Samples infos   | |
     |  |   [Microservice A]  &amp;lt;--Data--&amp;gt;  [Microservice B] &amp;lt;--Data--&amp;gt; [Microservice N-1] |      |                          | |
     |  +-------------------------^-----------------------^-------------------------^----+      +--------------------------+ |
     |                            |                       |                         |                                        |
     |              (Store/Retrieve)       (Write/Open Files)      (Sends data aggregations)                                 |
     |                            |                       |                         |                                        |
     +----------------------------v-----------------------v-------------------------v----------------------------------------+
     | +--------------------------------+ +--------------------------------+ +--------------------------------------------+  |
     | |        POSTGRESQL DB           | |             MINIO              | |                   DHIS2                    |  |
     | |     (Primary Data Store)       | |      (Object/File Storage)     | |           (External Data Recipient)        |  |
     | +--------------------------------+ +--------------------------------+ +--------------------------------------------+  |
     |               | (Reads Data)                                                                                          |
     |               |                                                                                                       |
     | +-------------v--------------------+                                                                                  |
     | |    APACHE SUPERSET (Dataviz)     |                                                                                  |
     | +----------------------------------+                                                                                  |
     |                                                                                                                       |
     +-----------------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The engineering team:
&lt;/h3&gt;

&lt;p&gt;This article is also for my fellow developers who built the 4S network under impossible constraints—limited budgets, legacy infrastructure, unrealistic timelines. My colleagues engineers writing scripts to detect disease patterns, configuring servers that never get enough resources. My teammates who's written documentation that nobody reads but everyone depends on. I'm talking about the people who made the story:&lt;/p&gt;

&lt;h4&gt;
  
  
  Cisse:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/mamadou-cisse-723b29114/" rel="noopener noreferrer"&gt;Cisse&lt;/a&gt; a.k.a "Celui qui fait bouger le monde", plays a crucial role in coordinating activities across the Institution Digital Factory team. His expertise extends to managing and preserving the integrity of biomedical data within the Institution. He works closely with stakeholders to validate specifications of new health applications. To uncover more about him, follow this &lt;a href="https://www.linkedin.com/in/mamadou-cisse-723b29114/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Mame Astou:
&lt;/h4&gt;

&lt;p&gt;As an integral member of the development team, &lt;a href="https://www.linkedin.com/in/mameastougassama" rel="noopener noreferrer"&gt;Mame Astou&lt;/a&gt; a.k.a "Madame La Directrice", craft robust and dynamic web applications while maintaining a keen eye for intuitive user interface design. She knows how to create user experiences that prioritize both aesthetic appeal and seamless usability. What would we be without her? Absolutely nothing. To uncover more about her, please visit this &lt;a href="https://www.linkedin.com/in/mameastougassama" rel="noopener noreferrer"&gt;page&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Diom:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.doyoubuzz.com/diom-sow" rel="noopener noreferrer"&gt;Diom&lt;/a&gt;, a.k.a "Le Grand Marabout de l'Architecture", is a DevOps engineer who bridges the gap between development and operations. With expertise in containerization technologies, cloud platforms, and monitoring solutions, he design and maintain scalable deployment environments while ensuring system reliability and security.&lt;/p&gt;

&lt;h4&gt;
  
  
  Abdoul Karim:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/mohamed-abdoul-karim-diop-76250b127/" rel="noopener noreferrer"&gt;Abdoul Karim&lt;/a&gt; is probably the pillar of the team, always ready to make concessions and take responsibility. His technical experience spans multiple domains. It would take me hours to explain why he is an excellent engineer. Just go and find out by yourself how great &lt;a href="https://www.linkedin.com/in/mohamed-abdoul-karim-diop-76250b127/" rel="noopener noreferrer"&gt;he is&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Mariama:
&lt;/h4&gt;

&lt;p&gt;Mariama a.k.a "La Sauveuse De Tous Les Hommes", has a deep knowledge of Scrum and agile principles. She guide the team through iterative development cycles while fostering continuous improvement and team collaboration. We are still waiting for that one day she will finally write a few lines of TypeScript. Access Mariama's comprehensive profile by following this link.&lt;/p&gt;

&lt;h4&gt;
  
  
  Birante:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://fr.linkedin.com/in/birantesy" rel="noopener noreferrer"&gt;Birante&lt;/a&gt; has an exceptional expertise that encompasses everything from custom UI animations and state management to integrating native device features and third-party services. He is able to deliver native-quality experiences across both iOS, Android and Web platforms. He secretly dreams about rewriting all the 4s platform using &lt;a href="https://www.youtube.com/watch?v=gcwzWzC7gUA" rel="noopener noreferrer"&gt;RoR&lt;/a&gt; applications. Here is a link to get the complete picture about Birante.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tidiane:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/adtidiane" rel="noopener noreferrer"&gt;Tidiane&lt;/a&gt;, a.k.a "Le Sage", a.k.a "The Biobank expert", is probably the wisest and most reserved member of the team. Tidiane is a seasoned backend developer who brings deep expertise in Django framework development. He excel at designing robust APIs and implementing complex business logic that powers modern web applications. If you know anyone who works at &lt;a href="https://www.modul-bio.com" rel="noopener noreferrer"&gt;Mbiolims&lt;/a&gt;, please tell them they should hire Tidiane. His background can be found &lt;a href="https://www.linkedin.com/in/amadou-tidiane-diallo-61065a41/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adrien:
&lt;/h4&gt;

&lt;p&gt;Aux âmes bien nées, la valeur n'attend point le nombre d'années. Adrien, the youngest in the team, is a software engineer with an extensive experience in developing RESTful APIs, managing database migrations, and implementing automated testing frameworks within Django projects. For additional information about Adrien, visit this link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guys, your dedication, your resilience, your ingenuity deserve recognition far beyond what they receive. Thank you.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The roadmap:
&lt;/h3&gt;

&lt;p&gt;Right now we're developing comprehensive features related to &lt;strong&gt;"case management"&lt;/strong&gt;. Those features will enable healthcare providers to track patient journeys from initial consultation through treatment completion, ensuring continuity of care and improved outcomes.&lt;/p&gt;

&lt;p&gt;We plan to extend our platform to handle a &lt;strong&gt;wider spectrum of medical conditions and syndromes&lt;/strong&gt; , transforming it from a specialized tool into a comprehensive healthcare management solution.&lt;/p&gt;

&lt;p&gt;Our platform will also align with the &lt;strong&gt;One Health approach&lt;/strong&gt; , recognizing the interconnection between human, animal, and environmental health.&lt;/p&gt;

&lt;p&gt;Data exchange with other healthcare systems, electronic health records, and medical devices, is something we need to work towards. We really need to meet evolving healthcare standards and prepare for international expansion. While I agree we didn't put enough efforts on this, compliance and interoperability remain central to our development strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;More on the topic:&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Writing about 4S implementation could fill volumes. For those ready to dig deeper into the technical and policy dimensions of public health surveillance, &lt;em&gt;and before I write the second part of this series&lt;/em&gt;, here are resources that expand on the key concepts discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/healthsites-io/cartographie-des-donn%C3%A9es-sanitaires-durgence-au-s%C3%A9n%C3%A9gal-474c3c3bec29" rel="noopener noreferrer"&gt;Mapping emergency health data in Senegal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Z8pa6BQN54w" rel="noopener noreferrer"&gt;How CARE transforms outbreaks into opportunities for Africa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=cZfzP3J2VxY" rel="noopener noreferrer"&gt;A new way to fight infectious diseases and predict outbreaks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stories.theglobalfund.org/early-detection-for-rapid-response-strengthening-disease-surveillance-across-west-africa" rel="noopener noreferrer"&gt;Early detection for rapid response: strengthening disease surveillance across West Africa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://institutpasteurdakar.sn/strengthening-epidemic-resilience-through-one-health-and-integrated-community-based-surveillance/" rel="noopener noreferrer"&gt;Strengthening epidemic resilience through one health and integrated community-based surveillance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kaikai.dev/blog/blog-1/ihe-for-senegal-a-look-back-at-the-ihe-training-week-6" rel="noopener noreferrer"&gt;Launch and training on medical data exchange in Senegal according to IHE standards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=pmiQza2kQmE" rel="noopener noreferrer"&gt;Dengue sylvatique : l’angle mort du diagnostic — Dr Idrissa Dieng&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some people we might want to collaborate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://data.humdata.org/" rel="noopener noreferrer"&gt;the Humanitarian Data Exchange&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://healthsites.io/" rel="noopener noreferrer"&gt;HealthSites.IO, I've contributed Python code for them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eyone.net/en/about-us" rel="noopener noreferrer"&gt;Eyone, improving the quality of medical care through technology.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://njureel.com/#accueil" rel="noopener noreferrer"&gt;Njureel, reinventing the proximity between healthcare professionals and patients&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geomatica.space/" rel="noopener noreferrer"&gt;Geomatica, one of the greatest company in geospatial data (The founder is a very good friend)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you learned something. If you found this article interesting, please share it &lt;a href="https://www.youtube.com/watch?v=K0HSD_i2DvA" rel="noopener noreferrer"&gt;around the world&lt;/a&gt;. Tell them there are people here who save lives with free and open source software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fsample.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnskm.xyz%2Fimages%2Fsample.jpg" title="Sample container" width="800" height="1065"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>software</category>
      <category>epidemiology</category>
      <category>python</category>
      <category>publichealth</category>
    </item>
  </channel>
</rss>
