class ThinkingSphinx::Attribute

Attributes - eternally useful when it comes to filtering, sorting or grouping. This class isn’t really useful to you unless you’re hacking around with the internals of Thinking Sphinx - but hey, don’t let that stop you.

One key thing to remember - if you’re using the attribute manually to generate SQL statements, you’ll need to set the base model, and all the associations. Which can get messy. Use Index.link!, it really helps.

Constants

SphinxTypeMappings

Attributes

query_source[RW]

Public Class Methods

new(source, columns, options = {}) click to toggle source

To create a new attribute, you’ll need to pass in either a single Column or an array of them, and some (optional) options.

Valid options are:

  • :as => :alias_name

  • :type => :attribute_type

  • :source => :field, :query, :ranged_query

Alias is only required in three circumstances: when there’s another attribute or field with the same name, when the column name is ‘id’, or when there’s more than one column.

Type is not required, unless you want to force a column to be a certain type (but keep in mind the value will not be CASTed in the SQL statements). The only time you really need to use this is when the type can’t be figured out by the column - ie: when not actually using a database column as your source.

Source is only used for multi-value attributes (MVA). By default this will use a left-join and a group_concat to obtain the values. For better performance during indexing it can be beneficial to let Sphinx use a separate query to retrieve all document,value-pairs. Either :query or :ranged_query will enable this feature, where :ranged_query will cause the query to be executed incremental.

Example usage:

Attribute.new(
  Column.new(:created_at)
)

Attribute.new(
  Column.new(:posts, :id),
  :as => :post_ids
)

Attribute.new(
  Column.new(:posts, :id),
  :as => :post_ids,
  :source => :ranged_query
)

Attribute.new(
  [Column.new(:pages, :id), Column.new(:articles, :id)],
  :as => :content_ids
)

Attribute.new(
  Column.new("NOW()"),
  :as   => :indexed_at,
  :type => :datetime
)

If you’re creating attributes for latitude and longitude, don’t forget that Sphinx expects these values to be in radians.

# File lib/thinking_sphinx/attribute.rb, line 81
def initialize(source, columns, options = {})
  super

  @type           = options[:type]
  @query_source   = options[:source]
  @crc            = options[:crc]
  @all_ints       = options[:all_ints]

  @type         ||= :multi    unless @query_source.nil?
  if @type == :string && @crc
    @type = is_many? ? :multi : :integer
  end

  source.attributes << self
end

Public Instance Methods

all_datetimes?() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 201
def all_datetimes?
  all_of_type?(:datetime, :date, :timestamp)
end
all_ints?() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 197
def all_ints?
  @all_ints || all_of_type?(:integer)
end
all_strings?() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 205
def all_strings?
  all_of_type?(:string, :text)
end
config_value(offset = nil, delta = false) click to toggle source

Returns the configuration value that should be used for the attribute. Special case is the multi-valued attribute that needs some extra configuration.

# File lib/thinking_sphinx/attribute.rb, line 144
def config_value(offset = nil, delta = false)
  if type == :multi
    multi_config = include_as_association? ? "field" :
      source_value(offset, delta).gsub(%r\s+/, " ").strip
    "uint #{unique_name} from #{multi_config}"
  else
    unique_name
  end
end
include_as_association?() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 135
def include_as_association?
  ! (type == :multi && (query_source == :query || query_source == :ranged_query))
end
live_value(instance) click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 186
def live_value(instance)
  object = instance
  column = @columns.first
  column.__stack.each { |method|
    object = object.send(method)
    return sphinx_value(nil) if object.nil?
  }

  sphinx_value object.send(column.__name)
end
to_select_sql() click to toggle source

Get the part of the SELECT clause related to this attribute. Don’t forget to set your model and associations first though.

This will concatenate strings and arrays of integers, and convert datetimes to timestamps, as needed.

# File lib/thinking_sphinx/attribute.rb, line 103
def to_select_sql
  return nil unless include_as_association? && available?

  separator = all_ints? || all_datetimes? || @crc ? ',' : ' '

  clause = columns_with_prefixes.collect { |column|
    case type
    when :string
      adapter.convert_nulls(column)
    when :datetime
      adapter.cast_to_datetime(column)
    when :multi
      column = adapter.cast_to_datetime(column)   if is_many_datetimes?
      column = adapter.convert_nulls(column, '0') if is_many_ints?
      column
    else
      column
    end
  }.join(', ')

  clause = adapter.crc(clause)                          if @crc
  clause = adapter.concatenate(clause, separator)       if concat_ws?
  clause = adapter.group_concatenate(clause, separator) if is_many?
  clause = adapter.downcase(clause)                     if insensitive?

  "#{clause} AS #{quote_column(unique_name)}"
end
type() click to toggle source

Returns the type of the column. If that’s not already set, it returns :multi if there’s the possibility of more than one value, :string if there’s more than one association, otherwise it figures out what the actual column’s datatype is and returns that.

# File lib/thinking_sphinx/attribute.rb, line 159
def type
  @type ||= begin
    base_type = case
    when is_many?, is_many_ints?
      :multi
    when @associations.values.flatten.length > 1
      :string
    else
      translated_type_from_database
    end

    if base_type == :string && @crc
      base_type = :integer
    else
      @crc = false unless base_type == :multi && is_many_strings? && @crc
    end

    base_type
  end
end
type_to_config() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 131
def type_to_config
  SphinxTypeMappings[type]
end
updatable?() click to toggle source
# File lib/thinking_sphinx/attribute.rb, line 180
def updatable?
  [:integer, :datetime, :boolean].include?(type) &&
  unique_name != :sphinx_internal_id &&
  !is_string?
end