Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chewy #23

Open
blackchestnut opened this issue Jun 10, 2017 · 0 comments
Open

Chewy #23

blackchestnut opened this issue Jun 10, 2017 · 0 comments

Comments

@blackchestnut
Copy link
Owner

toptal/chewy

Examples

# Model index 
class SuppliesIndex < Chewy::Index
  settings analysis: {
    analyzer: {
      lowercase: {
        tokenizer: 'standard',
        filter: ['lowercase']
      }
    },
  }

  define_type Supply do
    field :supplier_id, type: 'integer', index: :not_analyzed
    field :category_id, type: 'integer', index: :not_analyzed
    field :name, type: 'text', analyzer: :lowercase
    field :supplier_sku, type: 'text', analyzer: :lowercase
    field :manufacturer_sku, type: 'text', analyzer: :lowercase

    field :manufacturer,
      type: 'text',
      analyzer: :lowercase,
      fields: {
        raw: {
          type: 'keyword',
          index: :not_analyzed,
        }
      }

    field :price,
      type: 'float',
      value: ->(v) { v.prices.first&.price.to_f }
  end
end
# Queries
class ElasticSupply
  SEARCHABLE_FIELDS = %w(
    manufacturer
    manufacturer_sku
    name
    supplier_sku
  )

  # Return Supply filter with numbers of supplies.
  #
  # @example
  #   ElasticSupply.filter()
  #   or
  #   ElasticSupply.filter(supplier_id: 1)
  #
  def self.filter(supplier_id: nil)
    matches = []
    matches << { term: { supplier_id: supplier_id } } unless supplier_id.blank?
    SuppliesIndex.query({ bool: { must: matches } })
      .aggs({
        category: { terms: { field: 'category_id' } },
        manufacturer: { terms: { field: 'manufacturer.raw' } },
      })
      .limit(0)
      .aggs
  end

  # Find Supply by search query with pagination.
  #
  # @example
  #   ElasticSupply.search(query: '*foo*', supplier_id: 1, page: 1, per_page: 1)
  #   or
  #   ElasticSupply.search(query: '*foo*')
  #
  # @param query [String] - 'foo', 'foo*', '*foo*'
  # @param supplier_id [Integer] additional filter by supplier_id (optional)
  # @param page [Integer]
  # @param per_page [Integer]
  #
  # @return [Array<Supply>]
  def self.search(query:, supplier_id: nil, category_ids: nil, manufacturers: nil, page: 1, per_page: 20)
    ElasticSupply
      .full_search_raw(
        query: query,
        supplier_id: supplier_id,
        category_ids: category_ids,
        manufacturers: manufacturers,
      )
      .paginate(page: page, per_page: per_page)
      .load(scope: ->{ includes(:prices, :office_supplies) })
      .to_a
  end

  # Find total count items in the index by query.
  #
  # @example
  #   ElasticSupply.total_count(query: '*foo*')
  #   or
  #   ElasticSupply.total_count(query: '**', supplier_id: 1, manufacturers: ['KEYSTONE DENTAL'])
  #
  # @param query [String] - 'foo', 'foo*', '*foo*'
  # @param supplier_id [Integer] additional filter by supplier_id (optional)
  #
  # @return [Integer]
  def self.total_count(query:, supplier_id: nil, category_ids: nil, manufacturers: nil)
    ElasticSupply
      .full_search_raw(
        query: query,
        supplier_id: supplier_id,
        category_ids: category_ids,
        manufacturers: manufacturers,
      )
      .total_count
  end

  # Search by query in all fields.
  #
  # @param query [String] - 'foo', 'foo*', '*foo*'
  # @param supplier_id [Integer] additional filter by supplier_id
  #
  # @return [SuppliesIndex::Query]
  def self.full_search_raw(query:, supplier_id:, category_ids:, manufacturers:)
    matches = [{ query_string: { query: query } }]
    matches << { term: { supplier_id: supplier_id } } unless supplier_id.blank?

    if category_ids.present?
      categories_query = category_ids.map { |v| { match: { category_id: v } } }
      matches << { bool: { should: categories_query } }
    end

    if manufacturers.present?
      manufacturers_query = manufacturers.map do |v|
        { match: { 'manufacturer.raw': v } }
      end
      matches << { bool: { should: manufacturers_query } }
    end

    SuppliesIndex.query({ bool: { must: matches } })
  end

  # Search by query as prefix in all fields.
  #
  # @param query [String] the '*' is unnecessary: 'foo' is equivalent to the 'foo*'
  # @param supplier_id [Integer] additional filter by supplier_id
  #
  # @return [SuppliesIndex::Query]
  def self.prefix_search_raw(query:, supplier_id:)
    matches = SEARCHABLE_FIELDS.map do |field|
      { 'match_phrase_prefix' => { field => query } }
    end
    search = SuppliesIndex.query({ bool: { should: matches } })
    return search if supplier_id.blank?

    search.query(term: { supplier_id: supplier_id })
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant