<?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: Ahmad Ganjtabesh</title>
    <description>The latest articles on DEV Community by Ahmad Ganjtabesh (@agtabesh).</description>
    <link>https://dev.to/agtabesh</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%2F1321924%2F0eedd9fd-da7f-4367-bec9-45f1fa094c06.png</url>
      <title>DEV Community: Ahmad Ganjtabesh</title>
      <link>https://dev.to/agtabesh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agtabesh"/>
    <language>en</language>
    <item>
      <title>The Primary Responsibility of a Software Engineer: Delaying Decisions</title>
      <dc:creator>Ahmad Ganjtabesh</dc:creator>
      <pubDate>Thu, 10 Oct 2024 09:19:10 +0000</pubDate>
      <link>https://dev.to/agtabesh/the-primary-responsibility-of-a-software-engineer-delaying-decisions-4pj6</link>
      <guid>https://dev.to/agtabesh/the-primary-responsibility-of-a-software-engineer-delaying-decisions-4pj6</guid>
      <description>&lt;p&gt;At the heart of software engineering, our most visible task is building the features that businesses rely on. We work closely with stakeholders to develop the functionality that drives the business forward, whether it’s handling payments, managing customer data, or delivering personalized experiences to users. &lt;strong&gt;Delivering these features is critical&lt;/strong&gt;, but it’s not the most important part of the job.&lt;/p&gt;

&lt;p&gt;I believe that the &lt;strong&gt;primary responsibility&lt;/strong&gt; of a software engineer is to &lt;strong&gt;design systems that give the team flexibility to delay certain key decisions until later&lt;/strong&gt;, when there's more information available. Delaying decisions may sound counterintuitive, but it's a strategy that can significantly reduce risk, increase adaptability, and ultimately lead to more robust systems.&lt;/p&gt;

&lt;p&gt;Software development is full of uncertainties: business needs evolve, user behavior changes, data volume grows, and new technologies emerge. If we make key decisions too early - such as selecting a database, cloud provider, or framework - we may lock ourselves into choices that limit flexibility in the future. What might work well for a small project or MVP (Minimum Viable Product) could break down as the system scales or as business requirements change.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Importance of Delaying Decisions
&lt;/h4&gt;

&lt;p&gt;Making decisions with incomplete information can lead to technical debt. When we choose technology or architecture early on, it's often based on assumptions about how the system will behave in the future. But reality rarely matches those assumptions. By postponing decisions, we reduce the risk of locking ourselves into choices that don't hold up as the project evolves.&lt;/p&gt;

&lt;p&gt;Take, for example, the decision of &lt;strong&gt;choosing a database&lt;/strong&gt;. At the start of a project, you might not have a clear picture of the types of queries you'll need, the volume of data you'll store, or the complexity of relationships in the data. Committing to a specific database early could cause issues if the project later requires more complex querying, higher scalability, or better indexing. By delaying this decision - perhaps starting with an abstracted data access layer - you give yourself the flexibility to switch to a different database later without reworking large parts of the codebase.&lt;/p&gt;

&lt;p&gt;Delaying decisions isn't about avoiding responsibility or kicking the can down the road. It's about &lt;strong&gt;waiting for the right time to make decisions&lt;/strong&gt; - when you have more clarity on the system's real needs. This leads to better, more informed choices that are sustainable in the long term.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to Delay Decisions: Abstraction and Isolation
&lt;/h4&gt;

&lt;p&gt;The key to effectively delaying decisions is through &lt;strong&gt;abstraction&lt;/strong&gt; and &lt;strong&gt;isolation&lt;/strong&gt;. By isolating different layers of the system and abstracting them from one another, you can minimize the impact of changes to one part of the system when it's time to make a decision.&lt;/p&gt;

&lt;p&gt;For instance, in the case of choosing a &lt;strong&gt;cloud provider&lt;/strong&gt;, many companies start by tightly integrating their systems with specific services offered by platforms like AWS, Google Cloud, or Azure. But what happens if the business later wants to migrate to a different provider for cost reasons or regulatory compliance? If the system is tightly coupled to a single provider's APIs, switching becomes a painful and costly process. However, by abstracting cloud-specific logic behind interfaces or adopting cloud-agnostic solutions like Kubernetes, you delay the decision of committing fully to one provider. This gives you the flexibility to migrate or expand to multiple providers when the need arises, without significant rework.&lt;/p&gt;

&lt;p&gt;Abstraction can also apply to &lt;strong&gt;logging&lt;/strong&gt;, &lt;strong&gt;monitoring&lt;/strong&gt;, or even &lt;strong&gt;authentication&lt;/strong&gt;. Instead of choosing a logging framework early on and embedding it deep in your business logic, you can abstract logging behind a common interface. This allows you to start with a basic logging mechanism during development and later switch to a more advanced solution (like ELK stack or Datadog) as the project scales - without modifying the core of your application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Balancing with the Secondary Responsibility: Delivering Features
&lt;/h4&gt;

&lt;p&gt;While the primary responsibility is about creating flexibility and future-proofing systems, the &lt;strong&gt;secondary responsibility&lt;/strong&gt; of a software engineer is just as important: &lt;strong&gt;delivering features&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The business requires functionality to meet immediate goals - whether it's releasing a new product feature, enabling a payment system, or building an internal tool for operations. These features directly contribute to the value of the business, and it's our job to implement them efficiently and with quality. After all, the system won't be useful if it doesn't deliver the functionality that users and stakeholders need.&lt;/p&gt;

&lt;p&gt;However, delivering features can sometimes be at odds with the goal of delaying decisions. There is often pressure to deliver quickly, and it can be tempting to hardcode specific choices or skip the abstraction process to speed things up. For example, an engineer might choose a specific &lt;strong&gt;third-party authentication provider&lt;/strong&gt; and tightly integrate it into the code, believing that this will get the feature done faster. And in the short term, it might. But if the business later decides to switch providers, or add support for multiple authentication methods, the tightly-coupled implementation will lead to costly refactoring.&lt;/p&gt;

&lt;p&gt;This is where balancing both responsibilities becomes critical. While it's necessary to deliver features to meet business needs, engineers must ensure that those features are delivered in a way that keeps the system flexible. Abstracting key parts of the system and keeping components loosely coupled allows features to be built without locking the system into decisions that may no longer make sense in the future.&lt;/p&gt;

&lt;p&gt;For example, while delivering a feature that involves &lt;strong&gt;user data storage&lt;/strong&gt;, we might opt to use an abstracted data layer that allows us to switch databases later, rather than committing to one specific database right away. This way, we deliver the feature while still keeping the system adaptable for future changes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Delaying Decisions and Delivering Features Go Hand-in-Hand
&lt;/h4&gt;

&lt;p&gt;Ultimately, the two responsibilities - delaying decisions and delivering features - are not in conflict; they complement each other. By building systems that allow decisions to be postponed, engineers reduce the risk of technical debt and future-proof the system. And by delivering features thoughtfully, with abstraction and flexibility in mind, we ensure that business needs are met without compromising long-term adaptability.&lt;/p&gt;

&lt;p&gt;When both responsibilities are managed effectively, we create systems that &lt;strong&gt;deliver immediate business value through features that work well today&lt;/strong&gt;. At the same time, these systems &lt;strong&gt;remain flexible and adaptable to future changes&lt;/strong&gt;, allowing key decisions to be made when the right time comes.&lt;/p&gt;

&lt;p&gt;A strong software engineer understands that delivering features isn't just about solving today's problems - it's about ensuring that the system can grow and evolve smoothly in the future. This mindset leads to more maintainable, scalable, and resilient systems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion: A Balance for Sustainable Software Development
&lt;/h4&gt;

&lt;p&gt;In summary, while delivering features is critical and serves the immediate needs of the business, the &lt;strong&gt;primary responsibility&lt;/strong&gt; of a software engineer is to design systems that give the team the flexibility to make better decisions in the future. By abstracting key components, decoupling systems, and postponing decisions like choosing a database or cloud provider, we can create adaptable systems that evolve smoothly as requirements change.&lt;/p&gt;

&lt;p&gt;Balancing both responsibilities ensures that we're not only meeting the business's current needs but also protecting the long-term health and scalability of the system. In doing so, we set our teams up for success, now and in the future.&lt;/p&gt;

&lt;p&gt;Thank you for reading! Feel free to leave your comments below, and let’s stay connected on &lt;a href="https://www.linkedin.com/in/agtabesh" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://x.com/agtabesh1" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/agtabesh" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more insights and updates.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Speeding Up Go Concurrency: Unlocking the Power of Array Segmentation</title>
      <dc:creator>Ahmad Ganjtabesh</dc:creator>
      <pubDate>Mon, 01 Jul 2024 09:36:45 +0000</pubDate>
      <link>https://dev.to/agtabesh/speeding-up-go-concurrency-unlocking-the-power-of-array-segmentation-3dl2</link>
      <guid>https://dev.to/agtabesh/speeding-up-go-concurrency-unlocking-the-power-of-array-segmentation-3dl2</guid>
      <description>&lt;p&gt;Hey there, fellow Gophers! 🌟&lt;/p&gt;

&lt;p&gt;If you’ve been playing around with Go, you know that goroutines are the bread and butter of concurrency. But here’s the thing: when multiple goroutines try to access the same array, things can get messy real quick. You end up having to use mutex locks to avoid race conditions, and that can slow things down big time. But don’t worry, I’ve got a cool trick up my sleeve – segmenting the array to let goroutines work independently without stepping on each other’s toes. Let’s dive in!&lt;/p&gt;

&lt;h4&gt;
  
  
  Use Case: Crunching Big Data
&lt;/h4&gt;

&lt;p&gt;Imagine you’re building a web scraper that collects tons of data from different sources and dumps it all into a big array. You’ve got multiple goroutines fetching and processing data, and you want them to work concurrently to speed things up. But how do you keep them from getting in each other’s way?&lt;/p&gt;

&lt;h4&gt;
  
  
  The Mutex Approach
&lt;/h4&gt;

&lt;p&gt;First up, let’s see how we usually do it with mutex locks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000000&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&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;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c"&gt;// Example operation&lt;/span&gt;
                &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing complete"&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;In this setup, every goroutine locks the entire array before it writes to it. It’s safe, but man, is it slow!&lt;/p&gt;

&lt;h4&gt;
  
  
  The Segmentation Magic
&lt;/h4&gt;

&lt;p&gt;Now, let’s try something cooler. We’ll segment the array so each goroutine works on a different part without any locks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000000&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&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;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c"&gt;// Example operation&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing complete"&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;Here, each goroutine handles a specific segment of the array, and guess what – no locks needed! 🚀&lt;/p&gt;

&lt;h4&gt;
  
  
  Showdown: Benchmarking Both Approaches
&lt;/h4&gt;

&lt;p&gt;Alright, time to pit these two against each other and see which one’s faster. Here’s the benchmark code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000000&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ProcessWithMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&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;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
                &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ProcessWithSegmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&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;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkWithMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResetTimer&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="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProcessWithMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkWithSegmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResetTimer&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="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProcessWithSegmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run these benchmarks using &lt;code&gt;go test -bench .&lt;/code&gt; and let’s see the results!&lt;/p&gt;

&lt;p&gt;Benchmark Results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With Mutex:

&lt;ul&gt;
&lt;li&gt;Operations: 14&lt;/li&gt;
&lt;li&gt;Average Time Per Operation: ~82.48 ms (82,482,426 ns)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;With Segmentation:

&lt;ul&gt;
&lt;li&gt;Operations: 4948&lt;/li&gt;
&lt;li&gt;Average Time Per Operation: ~0.23 ms (231,511 ns)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Performance with Mutex:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only 14 operations in the testing period.&lt;/li&gt;
&lt;li&gt;Each operation took around 82.48 milliseconds.&lt;/li&gt;
&lt;li&gt;Mutexes are safe but introduce a lot of overhead and slow things down.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Performance with Segmentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A whopping 4948 operations in the same period.&lt;/li&gt;
&lt;li&gt;Each operation took just 0.23 milliseconds.&lt;/li&gt;
&lt;li&gt;By letting goroutines work on separate parts of the array, we cut out the need for locks and speed things up massively.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Conclusion:&lt;br&gt;
Segmentation blows mutexes out of the water! It’s about 357 times faster, making it a fantastic way to boost performance when dealing with large datasets and high concurrency.&lt;/p&gt;

&lt;p&gt;So next time you’re juggling goroutines, think about segmenting your data. It’s a game-changer!&lt;/p&gt;

&lt;p&gt;Happy coding, and feel free to share your thoughts and results in the comments below. Let’s make Go concurrency even more awesome! 🚀✨&lt;/p&gt;




&lt;p&gt;P.S: Thank you for reading! Feel free to leave your comments below, and let's stay connected on LinkedIn or follow me on Twitter or Github for more insights and updates in data mining and analytics.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Utilizing Locality-Sensitive Hashing (LSH) for Market Basket Analysis</title>
      <dc:creator>Ahmad Ganjtabesh</dc:creator>
      <pubDate>Thu, 07 Mar 2024 12:51:15 +0000</pubDate>
      <link>https://dev.to/agtabesh/utilizing-locality-sensitive-hashing-lsh-for-market-basket-analysis-59ph</link>
      <guid>https://dev.to/agtabesh/utilizing-locality-sensitive-hashing-lsh-for-market-basket-analysis-59ph</guid>
      <description>&lt;p&gt;Market Basket Analysis is a powerful technique used in retail and e-commerce to uncover associations between products frequently purchased together. By analyzing transactional data, businesses can identify patterns and make informed decisions to improve sales strategies, product placements, and customer experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Market Basket Analysis
&lt;/h2&gt;

&lt;p&gt;Market Basket Analysis operates on the principle of examining transactional data to uncover associations between products. The fundamental metric used in this analysis is "support," which measures the frequency of occurrence of item combinations in transactions. Common metrics derived from support include "confidence" and "lift," which provide insights into the strength and significance of associations between products.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://towardsdatascience.com/apriori-association-rule-mining-explanation-and-python-implementation-290b42afdfc6" rel="noopener noreferrer"&gt;Apriori&lt;/a&gt; algorithm is a fundamental technique in data mining for discovering frequent itemsets and deriving association rules from transactional data. It works by iteratively generating candidate itemsets, counting their support, and identifying frequent itemsets above a specified threshold.&lt;br&gt;
Despite its usefulness, the Apriori algorithm has limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Computational Complexity:&lt;/strong&gt; It can be computationally expensive, especially for large datasets, due to multiple passes over the data and generation of numerous candidate itemsets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Usage:&lt;/strong&gt; The algorithm requires significant memory to store candidate itemsets and support counts, which can be challenging for systems with limited resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inefficient for Sparse Data:&lt;/strong&gt; In datasets with high sparsity, the algorithm may produce many low-support itemsets, leading to inefficient pruning and reduced effectiveness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apriori Property Limitation:&lt;/strong&gt; Premature pruning based on the Apriori property may miss potentially interesting association rules if infrequent itemsets are pruned too aggressively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For scenarios where the Apriori algorithm's limitations are prohibitive, consider exploring alternative approaches such as Locality-Sensitive Hashing (LSH) for scalable and efficient market basket analysis.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction to Locality-Sensitive Hashing (LSH)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/similarity-search-part-5-locality-sensitive-hashing-lsh-76ae4b388203" rel="noopener noreferrer"&gt;Locality-Sensitive Hashing (LSH)&lt;/a&gt; is a technique used in data mining and similarity search to efficiently approximate similarity between data points in high-dimensional spaces. It is particularly useful for applications involving large datasets where traditional similarity search methods, such as exhaustive pairwise comparisons, become computationally expensive.&lt;/p&gt;

&lt;p&gt;The core idea behind LSH is to hash data points into buckets in such a way that similar data points are more likely to be hashed into the same bucket, while dissimilar points are likely to be hashed into different buckets. By organizing data into these buckets, LSH enables approximate nearest neighbor search, where similar data points can be efficiently retrieved by querying the corresponding buckets.&lt;/p&gt;

&lt;p&gt;LSH achieves this goal by employing hash functions that satisfy the locality-sensitive property, which means that the probability of collision (i.e., two data points being hashed into the same bucket) decreases with their similarity. LSH techniques are designed to balance the trade-off between precision (retrieving similar data points) and recall (retrieving all similar data points) based on application requirements.&lt;/p&gt;

&lt;p&gt;One of the key advantages of LSH is its ability to scale to large datasets with high-dimensional data spaces, such as text documents, images, and genetic sequences. By partitioning the data space into hash buckets, LSH reduces the search space for similarity queries, leading to significant improvements in computational efficiency.&lt;/p&gt;

&lt;p&gt;For this demonstration, we'll be utilizing the Groceries dataset, a commonly used benchmark dataset in Market Basket Analysis. This dataset comprises transactional records from a grocery store, with each transaction representing a customer's basket containing an assortment of items. We employ a GoLang library, &lt;a href="https://github/agtabesh/lsh" rel="noopener noreferrer"&gt;github/agtabesh/lsh&lt;/a&gt;, for implementing Locality-Sensitive Hashing (LSH) in our analysis.&lt;/p&gt;

&lt;p&gt;Let's go through the Go code step by step (you can find the source code &lt;a href="https://github.com/agtabesh/lsh-basket-analysis" rel="noopener noreferrer"&gt;here&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/csv"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"sort"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/agtabesh/lsh"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/agtabesh/lsh/types"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code starts by importing necessary packages. &lt;code&gt;context&lt;/code&gt;, &lt;code&gt;csv&lt;/code&gt;, &lt;code&gt;os&lt;/code&gt;, and &lt;code&gt;fmt&lt;/code&gt; are standard Go packages. &lt;code&gt;sort&lt;/code&gt; is used for sorting slices. &lt;code&gt;github/agtabesh/lsh&lt;/code&gt; contains the Locality-Sensitive Hashing (LSH) implementation, and &lt;code&gt;github.com/agtabesh/lsh/types&lt;/code&gt; contains custom types used in the LSH implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;datasetMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;readVectorsFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Groceries_dataset.csv"&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program starts by reading vectors (representing transactional data) from a CSV file named "Groceries_dataset.csv" using the &lt;code&gt;readVectorsFromFile&lt;/code&gt; function. It handles any errors that occur during file reading and returns an error if encountered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lsh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LSHConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SignatureSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&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;Next, the code defines the configuration for the Locality-Sensitive Hashing (LSH) algorithm. The SignatureSize parameter determine the size of the hash signature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;hashFamily&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lsh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewXXHASH64HashFamily&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignatureSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;similarityMeasure&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lsh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHammingSimilarity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lsh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewInMemoryStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code initializes components required for LSH, including the hash family (&lt;code&gt;hashFamily&lt;/code&gt;), similarity measure (&lt;code&gt;similarityMeasure&lt;/code&gt;), and storage mechanism (&lt;code&gt;store&lt;/code&gt;). In this case, &lt;code&gt;XXHASH64HashFamily&lt;/code&gt; is used for hashing, &lt;code&gt;HammingSimilarity&lt;/code&gt; for measuring similarity, and an in-memory store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lsh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLSH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;similarityMeasure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;store&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An LSH instance is created using the previously defined configuration, hash family, similarity measure, and store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&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="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;datasetMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;vectorID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VectorID&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vectorID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&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;The code iterates over the dataset map obtained from the CSV file, and adds them to the LSH instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"white bread"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;similarVectorsID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryByVector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample vector is defined, representing a product ("white bread"), and the &lt;code&gt;QueryByVector&lt;/code&gt; method is called to find similar vectors in the LSH instance. The number of similar vectors to retrieve is specified by the &lt;code&gt;count&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Items&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vectorID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;similarVectorsID&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;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;datasetMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;vectorID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Top&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code iterates over the IDs of similar vectors retrieved and aggregates the associated items from the dataset map, counting their occurrences. The top 10 associated items are extracted from the aggregated data, and the result is printed to the console.&lt;/p&gt;

&lt;p&gt;You can find the source code &lt;a href="https://github.com/agtabesh/lsh-basket-analysis" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, Market Basket Analysis combined with Locality-Sensitive Hashing provides a scalable and efficient solution for uncovering associations between products in large transactional datasets. By leveraging this approach, businesses can gain valuable insights to optimize their sales strategies and enhance customer experiences.&lt;/p&gt;




&lt;p&gt;P.S: Thank you for reading! Feel free to leave your comments below, and let's stay connected on &lt;a href="https://linkedin.com/in/agtabesh" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/agtabesh1" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/agtabesh" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more insights and updates in data mining and analytics.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>go</category>
      <category>computerscience</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
