Commit 9a8a84f1e1759f36dee890c83af994e6c68f535d
1 parent
33d339e2
Exists in
master
and in
1 other branch
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 < 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 | ... | ... |