Commit 9a8a84f1e1759f36dee890c83af994e6c68f535d

Authored by Andrew Kane
1 parent 33d339e2

Updated performant conversion docs to use database [skip ci]

Showing 1 changed file with 19 additions and 12 deletions   Show diff stats
README.md
... ... @@ -1598,19 +1598,27 @@ Product.reindex(:search_prices)
1598 1598  
1599 1599 ### Performant Conversions
1600 1600  
1601   -Split out conversions into a separate method so you can use partial reindexing, and cache conversions to prevent N+1 queries. Be sure to use a centralized cache store like Memcached or Redis.
  1601 +Cache conversions to prevent N+1 queries. For Postgres, create a migration with:
  1602 +
  1603 +```ruby
  1604 +add_column :products, :search_conversions, :jsonb
  1605 +```
  1606 +
  1607 +For MySQL, use `:json`, and for others, use `:text` with a [JSON serializer](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html).
  1608 +
  1609 +Next, create a separate method so you can use partial reindexing.
1602 1610  
1603 1611 ```ruby
1604 1612 class Product < ApplicationRecord
1605 1613 def search_data
1606 1614 {
1607 1615 name: name
1608   - }.merge(search_conversions)
  1616 + }.merge(search_conversions_data)
1609 1617 end
1610 1618  
1611   - def search_conversions
  1619 + def search_conversions_data
1612 1620 {
1613   - conversions: Rails.cache.read("search_conversions:#{self.class.name}:#{id}") || {}
  1621 + conversions: search_conversions || {}
1614 1622 }
1615 1623 end
1616 1624 end
... ... @@ -1620,17 +1628,17 @@ Create a job to update the cache and reindex records with new conversions.
1620 1628  
1621 1629 ```ruby
1622 1630 class ReindexConversionsJob < ApplicationJob
1623   - def perform(class_name)
  1631 + def perform(class_name, since)
1624 1632 # get records that have a recent conversion
1625 1633 recently_converted_ids =
1626   - Searchjoy::Search.where("convertable_type = ? AND converted_at > ?", class_name, 1.day.ago)
  1634 + Searchjoy::Search.where(convertable_type: class_name).where(converted_at: since..)
1627 1635 .order(:convertable_id).distinct.pluck(:convertable_id)
1628 1636  
1629 1637 # split into groups
1630 1638 recently_converted_ids.in_groups_of(1000, false) do |ids|
1631 1639 # fetch conversions
1632 1640 conversions =
1633   - Searchjoy::Search.where(convertable_id: ids, convertable_type: class_name)
  1641 + Searchjoy::Search.where(convertable_id: ids, convertable_type: class_name).where.not(user_id: nil)
1634 1642 .group(:convertable_id, :query).distinct.count(:user_id)
1635 1643  
1636 1644 # group conversions by record
... ... @@ -1640,12 +1648,11 @@ class ReindexConversionsJob &lt; ApplicationJob
1640 1648 end
1641 1649  
1642 1650 # write to cache
1643   - conversions_by_record.each do |id, conversions|
1644   - Rails.cache.write("search_conversions:#{class_name}:#{id}", conversions)
1645   - end
  1651 + attributes = conversions_by_record.map { |k, v| {id: k, search_conversions: v} }
  1652 + class_name.constantize.upsert_all(attributes)
1646 1653  
1647 1654 # partial reindex
1648   - class_name.constantize.where(id: ids).reindex(:search_conversions)
  1655 + class_name.constantize.where(id: ids).reindex(:search_conversions_data)
1649 1656 end
1650 1657 end
1651 1658 end
... ... @@ -1654,7 +1661,7 @@ end
1654 1661 Run the job with:
1655 1662  
1656 1663 ```ruby
1657   -ReindexConversionsJob.perform_later("Product")
  1664 +ReindexConversionsJob.perform_later("Product", 1.day.ago)
1658 1665 ```
1659 1666  
1660 1667 ## Advanced
... ...