<?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: Ruata Hmar</title>
    <description>The latest articles on DEV Community by Ruata Hmar (@ruatahmar).</description>
    <link>https://dev.to/ruatahmar</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4027505%2F72fae9cb-cd56-48c6-a696-3166113dd94f.jpeg</url>
      <title>DEV Community: Ruata Hmar</title>
      <link>https://dev.to/ruatahmar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ruatahmar"/>
    <language>en</language>
    <item>
      <title>Hash Indexes: What they are and their limitations</title>
      <dc:creator>Ruata Hmar</dc:creator>
      <pubDate>Fri, 02 Oct 2026 19:45:14 +0000</pubDate>
      <link>https://dev.to/ruatahmar/hash-indexes-what-they-are-and-their-limitations-29c4</link>
      <guid>https://dev.to/ruatahmar/hash-indexes-what-they-are-and-their-limitations-29c4</guid>
      <description>&lt;p&gt;Hash indexes are a type of database index used to speed up lookups by key.&lt;/p&gt;

&lt;p&gt;They are commonly implemented using a hash table, which uses hash function to map keys to locations where their corresponding values or references can be found.&lt;/p&gt;

&lt;p&gt;I wrote another blog going into more depth about hash maps and how they work. You can check it out &lt;a href="https://dev.to/ruatahmar/how-hash-maps-work-n8m"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How hash indexes work?
&lt;/h2&gt;

&lt;p&gt;Imagine you have a database containing users and their email addresses. If we want to find a user by their email, we could scan every record in the database until we find a match.&lt;/p&gt;

&lt;p&gt;That would take O(n) time which is very slow for lookups, especially as our dataset grows.&lt;/p&gt;

&lt;p&gt;Instead, we can use a hash index.&lt;/p&gt;

&lt;p&gt;A hash function takes a key, such as an email address, and converts it into a hash value. This value helps us locate the corresponding entry in the hash table without scanning every record.&lt;/p&gt;

&lt;p&gt;This gives hash indexes O(1) average-case lookup time (assuming a well-behaved hash function and a reasonable number of collisions, more on that on the hash map blog) which is pretty fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with memory
&lt;/h2&gt;

&lt;p&gt;Like all good things there's a catch. Hash indexes are typically maintained in memory because hash tables rely on fast access to their entries. If the hash table was stored in disk, they would distribute their keys in different areas of disk making it very hard to access different parts of the disk fast. Keeping the hash table in RAM allows lookups to happen much faster than repeatedly accessing random locations on disk.&lt;/p&gt;

&lt;p&gt;However, RAM is expensive compared to disk, which makes it limited.&lt;/p&gt;

&lt;p&gt;If we have a massive database, keeping the entire hash index in memory can become a problem. The index itself might be too large to fit in RAM, even if the actual data lives on disk. So hash indexes are better suited for smaller datasets that require frequent and fast access. &lt;/p&gt;

&lt;h2&gt;
  
  
  But RAM is volatile
&lt;/h2&gt;

&lt;p&gt;If our server crashes, the in-memory hash table disappears. If that hash table was the only place where our index existed, we'd lose the index and have to rebuild it.&lt;/p&gt;

&lt;p&gt;One solution is to use a write ahead log, or WAL.&lt;/p&gt;

&lt;p&gt;Think of a WAL as a log of changes that have been made, or are about to be applied, to our data structure.&lt;/p&gt;

&lt;p&gt;Whenever we perform a write or update, we first append the corresponding change to the log on disk before applying it to the in-memory index. This is the basic idea behind write ahead logging.&lt;/p&gt;

&lt;p&gt;We store the log on disk because we need the changes to survive a crash. If the server goes down, we can use the log to recover the changes that were recorded, rather than losing everything when RAM is cleared.&lt;/p&gt;

&lt;p&gt;Another neat thing about this is that WALs are written sequentially.&lt;/p&gt;

&lt;p&gt;Instead of jumping around the disk to update lots of different locations, we can append changes to the end of a log. Sequential writes are generally much more efficient than random disk writes, especially on traditional hard drives.&lt;/p&gt;

&lt;p&gt;The WAL doesn't magically make every operation faster though. It provides durability and supports recovery, while sequential appends can also make the write path more efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  No range queries
&lt;/h2&gt;

&lt;p&gt;Hash indexes have one more major limitation: they don't support efficient range queries.&lt;/p&gt;

&lt;p&gt;A range query is a query that retrieves records whose keys fall between two values.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A hash function distributes keys according to their hash values, not their original order.&lt;/p&gt;

&lt;p&gt;This means that even if the original keys are ordered, their corresponding hash values won't preserve that ordering.&lt;/p&gt;

&lt;p&gt;If we want to find all keys within a particular range, we generally have to examine the entries and check which ones match. That can take O(n) time in a basic hash-table implementation.&lt;/p&gt;

&lt;p&gt;This is where other index structures, such as B-tree indexes perform better.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, basically
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hash indexes are useful when we need fast exact-key, hash tables provide O(1) average-case reads and writes.&lt;/li&gt;
&lt;li&gt;Hashing doesn't preserve key order and are not good for ranged queries.&lt;/li&gt;
&lt;li&gt;Hash tables can consume a lot of RAM, so its better for smaller datasets.&lt;/li&gt;
&lt;li&gt;A write-ahead log helps recover changes after a crash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, choosing an index comes down to understanding the kind of queries your application needs to perform and the trade-offs you're willing to make.&lt;/p&gt;

&lt;p&gt;That's it for my learnings on this topic, please correct me if I'm wrong&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>database</category>
      <category>performance</category>
      <category>learning</category>
    </item>
    <item>
      <title>How hash maps work.</title>
      <dc:creator>Ruata Hmar</dc:creator>
      <pubDate>Thu, 01 Oct 2026 15:00:32 +0000</pubDate>
      <link>https://dev.to/ruatahmar/how-hash-maps-work-n8m</link>
      <guid>https://dev.to/ruatahmar/how-hash-maps-work-n8m</guid>
      <description>&lt;p&gt;This blog is a result of a short rabbit hole i went through as a part of me learning about hash indexing. I have also written a blog on hash indexing, you can check it out &lt;a href="https://dev.to/ruatahmar/hash-indexes-what-they-are-and-their-limitations-29c4"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Firstly, what problem does a hash map solve?
&lt;/h1&gt;

&lt;p&gt;Imagine you have an array:&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="n"&gt;names&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;Bruh&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;Bro&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;Dude&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;Bob&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;If I ask you to find &lt;code&gt;"Bob"&lt;/code&gt;, you might scan the array until you find it.&lt;/p&gt;

&lt;p&gt;Scanning through an array take O(n) time. &lt;/p&gt;

&lt;p&gt;But image if you could calculate exactly where the value should live, instead of searching for it?&lt;/p&gt;

&lt;p&gt;That's the central idea behind a hash map.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01vbbqytqxkpvzwdrf8x.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01vbbqytqxkpvzwdrf8x.png" alt="hash map mechanism" width="623" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hash function doesn't usually return an array index directly. It produces a hash value (using a hash function), which the hash map then converts into an index.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is a hash function?
&lt;/h1&gt;

&lt;p&gt;Simply put a hash function takes an input and transforms it into a number.&lt;/p&gt;

&lt;p&gt;For example, imagine we create a simple hash function:&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;hash_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&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;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ord()&lt;/code&gt; gives us the numeric value of a character.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;"cat"&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; → 99&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; → 97&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt; → 116&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;p&gt;h("cat")=99+97+116=312&lt;/p&gt;

&lt;p&gt;This function converts strings into numbers. That's hashing.&lt;/p&gt;

&lt;p&gt;You will notice &lt;code&gt;"act"&lt;/code&gt; also produces 312, because addition doesn't care about character order.Real hash functions are better designed to distribute keys more effectively.&lt;/p&gt;

&lt;p&gt;We need numbers because arrays use integer indices. Suppose our hash map uses an underlying array with 10 slots, indexed from 0 to 9. Our hash values might be much larger than 9, so we need to turn them into valid array indices. &lt;/p&gt;

&lt;p&gt;A simple approach is the modulo operator:&lt;/p&gt;

&lt;p&gt;index=h(key)mod capacity&lt;/p&gt;

&lt;p&gt;For "cat": 312mod10=2&lt;br&gt;
For "dog": 314mod10=4&lt;/p&gt;

&lt;p&gt;Now we have valid array indices.&lt;/p&gt;

&lt;p&gt;Our hypothetical hash table&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9yx5aw7ri10c78jf1otp.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9yx5aw7ri10c78jf1otp.png" alt="hypothetical hash table" width="627" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the basic mechanism behind a hash map: hash the key, calculate an index, and use the underlying array to access the entry.&lt;/p&gt;

&lt;p&gt;A hash function does not have to be cryptographically secure to work well in a hash map. General-purpose hash functions and cryptographic hash functions solve different problems.&lt;/p&gt;

&lt;p&gt;For example, SHA-256 is designed for cryptographic uses. A programming language's built-in hashing mechanism is generally designed around efficient data-structure operations and its own requirements.&lt;/p&gt;
&lt;h1&gt;
  
  
  What happens when two keys get the same index?
&lt;/h1&gt;

&lt;p&gt;I think this is probably everyone’s first question.  &lt;/p&gt;

&lt;p&gt;Suppose we insert &lt;code&gt;"cat"&lt;/code&gt; and &lt;code&gt;"tac"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our terrible hash function gives both strings the same hash because their characters add up to the same number. Both end up at index 2. This is called a collision. &lt;/p&gt;

&lt;p&gt;And collisions aren't just a problem with bad hash functions. Even good hash functions produce collisions when mapping a huge number of possible keys into a finite number of array slots. Collisions don't mean the hash map is broken. Collision resolution is part of the data structure's design.&lt;/p&gt;

&lt;p&gt;There are two major strategies for handling them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Strategy A: Separate chaining
&lt;/h2&gt;

&lt;p&gt;Each array slot holds a collection of entries, often a linked list or another small structure (like an array).&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1ilshk1nruqeu4ynphw.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1ilshk1nruqeu4ynphw.png" alt="chaining" width="637" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Index 0:  empty
Index 1:  empty
Index 2:  cat -&amp;gt; tac -&amp;gt; act
Index 3:  empty
Index 4:  dog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When multiple keys hash to the same index, they share that bucket.&lt;/p&gt;

&lt;p&gt;To look up &lt;code&gt;"tac"&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hash &lt;code&gt;"tac"&lt;/code&gt; to get index 2.&lt;/li&gt;
&lt;li&gt;Go to bucket 2.&lt;/li&gt;
&lt;li&gt;Search the entries in that bucket.&lt;/li&gt;
&lt;li&gt;Compare the actual keys to find &lt;code&gt;"tac"&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Strategy B: Open addressing
&lt;/h2&gt;

&lt;p&gt;Instead of storing a collection inside each bucket, every entry lives directly in the array. If the desired slot is occupied, the hash map searches for another available slot according to a probing strategy.&lt;/p&gt;

&lt;p&gt;For example, with linear probing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Index 0:  empty
Index 1:  empty
Index 2:  cat
Index 3:  tac    &amp;lt;- goes to the next available slot
Index 4:  dog
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To find &lt;code&gt;"tac"&lt;/code&gt;, the map starts at index 2, sees &lt;code&gt;"cat"&lt;/code&gt;, checks the next slot, and finds &lt;code&gt;"tac"&lt;/code&gt; at index 3. There are more sophisticated probing strategies, but that's the core idea.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resizing
&lt;/h1&gt;

&lt;p&gt;Imagine the underlying array has 10 slots, and you keep inserting hundreds of entries.&lt;/p&gt;

&lt;p&gt;Eventually, the table gets crowded. Collisions become more frequent, and operations slow down.&lt;/p&gt;

&lt;p&gt;Many hash maps solve this by resizing the underlying array and redistributing the entries.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
Capacity = 10
Entries  = 8

Resize:

After:
Capacity = 20
Entries  = 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entries generally need to be placed again because their indices depend on the table's capacity:&lt;/p&gt;

&lt;p&gt;index=h(key)mod capacity&lt;/p&gt;

&lt;p&gt;If the capacity changes, the index can change too.&lt;/p&gt;

&lt;p&gt;Resizing is expensive when it happens.&lt;/p&gt;

&lt;h1&gt;
  
  
  Time analysis
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Average case&lt;/th&gt;
&lt;th&gt;Worst case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Insert&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lookup&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why is the average case constant time?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculating an index is constant time.&lt;/li&gt;
&lt;li&gt;Calculating a hash takes time based on the key's size.&lt;/li&gt;
&lt;li&gt;Accessing an array slot is constant time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Strictly speaking, hashing a string of length k can take O(k) time if the hash must be calculated from scratch. So the usual O(1) claim assumes bounded-size keys or treats hash computation as constant time.&lt;/p&gt;

&lt;p&gt;The worst case happens when many keys collide or cluster together, forcing the map to examine many entries.&lt;/p&gt;

&lt;p&gt;But in chaining, there are multiple values in an bucket, so if there are m values inside a bucket why does it not take O(m) time to scan through a bucket ?&lt;/p&gt;

&lt;p&gt;This is because of an important variable called the load factor;&lt;/p&gt;

&lt;p&gt;α=n/m&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;n = number of entries.&lt;/li&gt;
&lt;li&gt;m = number of buckets.&lt;/li&gt;
&lt;li&gt;α = average number of entries per bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our example:&lt;/p&gt;

&lt;p&gt;α=1000/100​=10&lt;/p&gt;

&lt;p&gt;If the load factor stays bounded as the table grows, and hashing distributes keys reasonably well, the expected time spent searching a bucket remains constant. Therefore O(α) == O(1) in such conditions. &lt;/p&gt;

&lt;h1&gt;
  
  
  Mini hash map
&lt;/h1&gt;

&lt;p&gt;Lastly this is a mini hash map class i made in python (using the same old crappy hash function)&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;Hash_Map&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;__init__&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="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&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;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&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;hash_function&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="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_index&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="n"&gt;key&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;capacity&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set&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="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_oldVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;oldKey&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&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;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&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;get&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="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;old_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;old_key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&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;val&lt;/span&gt;

        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>computerscience</category>
      <category>learning</category>
      <category>python</category>
      <category>career</category>
    </item>
    <item>
      <title>Reverse Indexing and Clustering.</title>
      <dc:creator>Ruata Hmar</dc:creator>
      <pubDate>Thu, 13 Aug 2026 20:39:03 +0000</pubDate>
      <link>https://dev.to/ruatahmar/wilts-reverse-indexing-and-clustering-3ecg</link>
      <guid>https://dev.to/ruatahmar/wilts-reverse-indexing-and-clustering-3ecg</guid>
      <description>&lt;p&gt;What I learnt this week:&lt;/p&gt;

&lt;h1&gt;
  
  
  Reverse Indexing
&lt;/h1&gt;

&lt;p&gt;I am making a YouTube search application that allows you to search videos that you have saved in your account. This lead me to learning about how searches work and how they are optimised. One of the biggest thing i learnt was about reverse indexing. &lt;/p&gt;

&lt;p&gt;If you've worked with SQL databases before you'd know that data is stored in tables with a primary key used to index through the entries. Of course you can add other indexes as well, this is regular indexing, but it has a major limitation for search speeds. Imagine this table below (maybe insert table pic), if you wanted to search for a title "x" in this you'd have to go through all the entries using the index and match each entry's value to the value searched. This takes O(n) time which is not very fast. &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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8xry1gnscexol2gip2be.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8xry1gnscexol2gip2be.png" alt="A simple PostgreSQL table" width="454" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where reverse indexing comes. Reverse indexing is when the entry values are instead used as the indexes and the values they hold are references to the rows that store these values.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F342u4cy91nr8dxcogu17.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F342u4cy91nr8dxcogu17.png" alt="Reverse Index example" width="447" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you don't have to go through all records to find the entry and can just search in the value index. &lt;/p&gt;

&lt;p&gt;PostgreSQL is my database of choice, so i learnt that PostgreSQL implements reverse indexing using a &lt;code&gt;tsvector&lt;/code&gt;(text search vector) function which converts a column(or columns) of a table to a vector that represents reverse indexes. &lt;code&gt;tsquery&lt;/code&gt; is a function used to convert the search query in a form that can be easily used to match the &lt;code&gt;tsvector&lt;/code&gt; values to find the result faster.&lt;/p&gt;

&lt;p&gt;Finally there's a &lt;code&gt;GIN&lt;/code&gt; or Generalised Inverted Index, which is the actual index structure PostgreSQL uses under the hood for &lt;code&gt;tsvector&lt;/code&gt; columns. Think of it like an index but for every unique word, it keeps a list of which rows that word shows up in, so a search for a word goes straight to the word's row to find where the word shows up instead of scanning every row.&lt;/p&gt;

&lt;p&gt;This is the first layer of optimisation for my search feature. Depending on the results, I'll decide if it needs more optimisation or not.&lt;/p&gt;

&lt;h1&gt;
  
  
  Clustering
&lt;/h1&gt;

&lt;p&gt;This is something i revisited on reading Algorithm design by  Jon Kleinberg and Éva Tardos. Clustering is basically grouping of elements based on how similar they are. Pretty easy. Now how do we know how similar two elements are? Well we use a distance function duhh and obvious enough smaller distance = more similar. Now there are some basic rules for this distance function &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;d(a,a) = 0, basically for the same element distance is zero meaning its 100% similar&lt;/li&gt;
&lt;li&gt;d(a,b) &amp;gt; 0, different elements have positive distance&lt;/li&gt;
&lt;li&gt;d(a,b) = d(b,a), distance between 2 elements is similar no matter where you start from&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  K-clustering
&lt;/h2&gt;

&lt;p&gt;K-clustering basically means grouping a set S into k number of clusters. There's a very easy way to think about doing this and this is where a new term comes up: spacing. Spacing is the smallest distance between two elements that belong to different clusters.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faeoe2isd4d9m3kerck99.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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faeoe2isd4d9m3kerck99.png" alt="Spacing example" width="434" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spacing tells you how close 2 clusters are to coming in contact. Now if we want clusters to be as distinct as possible we would want 2 clusters to have maximum spacing in between them. This is called maximum spacing clustering. There may be different ways to cluster a set but I'll focus on the clustering with the max spacing. &lt;/p&gt;

&lt;p&gt;An easy algorithm proposed for maximum space clustering is Kruskal's algorithm but with slight tweaks. We merge nearby points as early as possible. we simply merge points in order of closeness until k clusters are formed. a different approach could also be to just delete k-1 of the max distance edges from a minimum spanning tree and it would result in a max spacing cluster.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
