<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="143290" data-post-id="143290">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steven7" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steven7
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks again for the helpful suggestions. Please allow me to make some clarifications though as I kinda skimped through a few requirements. My very first original design is actually ETS based with the following forma (each row is well, a row in the ETS)t:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{"doc_uuid1", %{"foo" =&gt; 0.123, "bar" =&gt; 0.777, ...}}
{"doc_uuid2", %{"foz" =&gt; 0.223, "zet" =&gt; 0.001, ...}}
...
{"doc_uuid1000000", %{"foo" =&gt; 0.93, "zet" =&gt; 0.1, ...}}
</code></pre>
<p>where the ID of the ETS table is the ID of my document and the value is just a plain Map. Now on average the Map only contains about 200-400 KV pairs, as I store it in a “sparse” way, as in if “doc_uuid1” don’t have the words “zet” it won’t even exists in the KV pair. Now my use case is actually, a new document being ingested, say <code>{doc_id, query_vector} = {"doc_uuid1000001", %{"foo" =&gt; 0.01, "zot" =&gt; 0.1}}</code>, a relatively short one for the sake of the argument, I would like to know out of the 1M documents which one has a high dot product, then I will actually append this to to ETS table as well. But as you well know,</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">fun = :ets.fun2ms(fn {doc_uuid, vector} when dot_product(query_vector, vector) &gt; 0.5 -&gt; id end)
:ets.select(:stored_vectors, fun)
</code></pre>
<p>won’t work. But reading your suggestion, and please correct me if I am wrong, I could potentially store my data in the ETS as such instead:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{{"doc_uuid1", "foo"}, 0.123}
{{"doc_uuid1", "bar"}, 0.777}
{{"doc_uuid2", "foz"}, 0.223}
...
</code></pre>
<p>And perhaps I can pull <code>fun2ms</code> retrieving on the entries, like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">query_keys = Map.keys(query_vector)
fun = :ets.fun2ms(fn {{doc_uuid, key}, vector} when key in Map.keys -&gt; {{doc_uuid, key}, vector} end)
:ets.select(:stored_vectors, fun)
</code></pre>
<p>Then perhaps I can do a <code>Enum.group_by</code> on the results to compute the final result I want, which is the ID of the documents that have the dot product of &gt; 0.5.</p>
<p>P/S: Off topic, your book if the first book that our company bought when we switched our main stack to Elixir/Erlang and we have all learnt a lot from it.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143290" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-143290" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143290"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="143308" data-post-id="143308">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="LostKobrakai" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/LostKobrakai/120/3072_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  LostKobrakai
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="steven7" data-post="22" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>But reading your suggestion, and please correct me if I am wrong, I could potentially store my data in the ETS as such instead:</p>
</blockquote>
</aside>
<p>That’s what you want to do. Storing data in <code>{name, map}</code> doesn’t help you get the benefits of storing data in ETS.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143308" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-143308" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143308"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="143310" data-post-id="143310">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lucaong" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lucaong/120/21794_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lucaong
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Does the detection of vectors whose product is &gt; k need to be exact, or would it be ok to get an approximate answer? If so, another possibility is to first select a smaller set of candidate vectors that are more likely to satisfy the condition, and then perform the exact dot product only on those candidates. This kind of technique is quite common in recommender systems, and usually relies on some kind of locality-sensitive hashing (LSH).</p>
<p>An LSH is a kind of hashing function with the property that items that are “close to each other” (according to a specific definition of distance) produce similar hashes.</p>
<p>For similar situations (lots of vectors, goal to find nearest neighbors of a given one) in the past I used LSH schemes quite successfully. In my case though, my metric was the cosine distance: depending on your application, that specific LSH scheme might or might not be a good solution for dot products.</p>
<p>Finally, if your vectors are sparse, but you can batch-process them in advance, you might benefit from some dimensionality reduction technique, to transform them into lower-dimentional, less sparse vectors that still retain the original relative distances as much as possible.</p>
<p>I hope this helps, and sorry for the noise in case this doesn’t apply to your case <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143310" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-143310" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143310"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="143311" data-post-id="143311">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="steven7" data-post="22" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>Now on average the Map only contains about 200-400 KV pairs</p>
</blockquote>
</aside>
<p>That sounds a bit more promising, though doing a million lookups will still require some time.</p>
<aside class="quote no-group" data-username="steven7" data-post="22" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>And perhaps I can pull <code>fun2ms</code> retrieving on the entries, like:</p>
</blockquote>
</aside>
<p>You could store <code>{{doc_id, term}, frequency}</code> tuples into ETS, and then invoke <code>:ets.match(:stored_vectors, {{doc_id, term},  :"$1"})</code> to get the frequency.</p>
<p>One question: how frequent are these terms, i.e. how many documents will on average contain the same term?</p>
<aside class="quote no-group" data-username="steven7" data-post="22" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>P/S: Off topic, your book if the first book that our company bought when we switched our main stack to Elixir/Erlang and we have all learnt a lot from it.</p>
</blockquote>
</aside>
<p>Happy to hear that!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143311" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-143311" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143311"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="143426" data-post-id="143426">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steven7" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steven7
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sasajuric" data-post="25" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>One question: how frequent are these terms, i.e. how many documents will on average contain the same term?</p>
<p><img src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/40.png" alt="" width="20" height="20" role="presentation"> steven7:</p>
</blockquote>
</aside>
<p>Well even after all the stop words removal, lemmatization I still find that usually ~85% document would contains at least one overlapped items with the query document. As in, if I have 1M documents already stored and when a new query document is ingested about 800K documents would have at least one overlapped term. Well I will need to optimise my algorithm if I were to use :ets as if I just retrieve the frequency using <code>:ets.match</code> I would lose the term, imagine the following scenario:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">ETS
{{"uuid1", "a"}, 0.005},
{{"uuid1", "b"}, 0.800}

New Document Terms
%{"a" =&gt; 0.5, "c" =&gt; 0.1}
</code></pre>
<p>If I just extract the frequency from the ETS I wouldn’t know to multiply it with 0.5 or 0.1, unless I changed my algorithm to handle one term at a time as such probably:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Enum.map(new_document_terms, fn {k, v} -&gt; :ets.match() ...  end)
</code></pre>
<p>But yeah thanks for the suggestions I would definitely try it out and see how does it perform against my other solution based in mostly PostgreSQL/MADlib/PL/python3u</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143426" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-143426" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143426"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="143456" data-post-id="143456">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="steven7" data-post="26" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>Well even after all the stop words removal, lemmatization I still find that usually ~85% document would contains at least one overlapped items with the query document.</p>
</blockquote>
</aside>
<p>Could you analyze the overlap distribution across terms? If most of the terms are mostly not overlapping, then I think you might profit from having mapping organized as <code>term -&gt; list({document_id, frequency})</code>. This could be easily achieved with a bag ets table (duplicate_bag might give you faster insertion times).</p>
<p>The reasoning here is that instead of querying 1M of other documents, you’d only make about 300 lookups (one per each term in the input document). If most terms are present in a relatively small fraction of the documents, this might work much faster. So basically, something like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">new_document_terms
# for the terms of the new document, collect {document_id, frequency_product} pairs
|&gt; Stream.flat_map(fn {term, frequency} -&gt;
  Enum.map(
    frequencies(term), # this function returns list({document_id, frequency})
    fn {document_id, existing_frequency} -&gt; {document_id, frequency * existing_frequency} end
  )
end)
# aggregate by document_id and compute the similarity
|&gt; Enum.reduce(
  %{},
  fn {document_id, frequency_product}, similarities -&gt;
    Map.update(similarities, document_id, frequency_product, &amp;(&amp;1 + frequency_product))
  end
)
# take only similar documents
|&gt; Enum.filter(fn {_document_id, similarity} -&gt; similarity &gt; 0.5 end)
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143456" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-143456" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143456"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="143752" data-post-id="143752">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steven7" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steven7
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sasajuric" data-post="27" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>Could you analyze the overlap distribution across terms?</p>
</blockquote>
</aside>
<p>Well the thing is some common words does have a huge number of overlap with other documents in the ETS but however:</p>
<aside class="quote no-group" data-username="sasajuric" data-post="27" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>you’d only make about 300 lookups (one per each term in the input document)</p>
</blockquote>
</aside>
<p>This design might be just what I need! I will run more tests to confirm this. AFAIK, I will only be doing 300 ETS lookup (which is O(1)) and I just need to gauge the <code>Enum.reduce/filter</code> part.</p>
<aside class="quote no-group" data-username="sasajuric" data-post="27" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>(duplicate_bag might give you faster insertion times)</p>
</blockquote>
</aside>
<p>I faced exactly this issue with <code>bag</code> when I have 1M documents and each have about 200 “rows” to be inserted into the ETS (a 200M rows ETS). Even using <code>public</code> table and <code>write_concurrency: true/false</code> and performing the insertion on both serial/multi process is so excruciatingly slow but <code>duplicate_bag</code> saved the day. Thanks for the heads up beforehand.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143752" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-143752" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143752"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="143759" data-post-id="143759">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="steven7" data-post="28" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>This design might be just what I need! I will run more tests to confirm this. AFAIK, I will only be doing 300 ETS lookup (which is O(1)) and I just need to gauge the <code>Enum.reduce/filter</code> part.</p>
</blockquote>
</aside>
<p>I wouldn’t open the champagne quite yet <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"><br>
If there are a lot of terms which are present in many documents, then this approach might end up being slow, maybe even slower than your original take. But anyway, give it a try, and let us know how it went.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143759" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-143759" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143759"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="143763" data-post-id="143763">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steven7" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steven7
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sasajuric" data-post="29" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>If there are a lot of terms which are present in many documents, then this approach might end up being slow, maybe even slower than your original take. But anyway, give it a try, and let us know how it went.</p>
</blockquote>
</aside>
<p>Ahh you’re right, the bottleneck is now at the <code>Map.update</code> part due to too many documents having overlapped terms.</p>
<aside class="quote no-group quote-modified" data-username="sasajuric" data-post="27" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>|&gt; Stream.flat_map(fn {term, frequency} → Enum.map( frequencies(term), # this function returns list({document_id, frequency}) fn {document_id, existing_frequency} → {document_id, frequency * existing_frequency} end ) end)</p>
</blockquote>
</aside>
<p>EDIT: I am having a crazy idea in mind where instead of returning a list of <code> {document_id, frequency * existing_frequency}</code> to the next <code>Enum.reduce</code> which is kinda the bottleneck (probably due to immutability), I would push the results of <code>frequency * existing_frequency</code> to a “temporary” ETS <em>or</em> some other storage where I would perform the <code>Enum.reduce</code> there.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143763" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-143763" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143763"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="143771" data-post-id="143771">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="steven7" data-post="30" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>Ahh you’re right, the bottleneck is now at the <code>Map.update</code> part due to too many documents having overlapped terms.</p>
</blockquote>
</aside>
<p>Yeah. This is why I asked about term distribution. If you don’t have a lot of highly overlapping terms, then the algo might work just fine.</p>
<aside class="quote no-group" data-username="steven7" data-post="30" data-topic="25313">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/s/8baadc/48.png" class="avatar"> steven7:</div>
<blockquote>
<p>I am having a crazy idea in mind</p>
</blockquote>
</aside>
<p>This would work if the sum was an integer. Then you could use <a href="http://erlang.org/doc/man/ets.html#update_counter-3" rel="nofollow">update_counter</a> to quickly aggregate.</p>
<p>However, this isn’t the case here, but I don’t think all is lost. You could use Flow to leverage parallelism and fetch each term from a separate process, and then aggregate each document in a separate process. I’ll see if I can make the sketch later.</p>
<p>But either way, I think that this approach of groupping per terms will only work if most of the terms are fairly scarce.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="143771" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/efficient-way-to-perform-vector-dot-product/25313/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-143771" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="143771"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/25313/load_more?page=4">Load more posts (3 remaining)</a>
</div></template></turbo-stream>