【问题标题】:Sphinx searching on migrated application data failingSphinx 搜索迁移的应用程序数据失败
【发布时间】:2014-08-15 07:17:33
【问题描述】:

在迁移的数据 rails 2.3.10 应用程序上创建一个 rails 3.2.18 应用程序。 数据现在已完全编入索引(感谢 Pat!),但是搜索却出现了问题(由于旧版 SphinxQL 协议或旧版应用程序代码)。

我已经设法按照来自 this release note 的信息运行了一个初始化程序(sphinx 是 2.1.8,ts 是 3.1.1)一直在尝试照照镜子并告诉那个家伙给 RTFM

ThinkingSphinx::SphinxQL.functions!

并在 thinking_sphinx.yml 中添加了 utf 位

  bin_path: /usr/local/bin
  pid_file: /Users/me/r/fna/shared/tmp/searchd.pid
  configuration_file: /Users/me/r/fna/config/development.sphinx.conf
  log: /Users/me/r/fna/log/searchd.log
  query_log: /Users/me/r/fna/log/searchd.query.log
  indices_location: /Users/me/r/fna/shared/sphinx
  64bit_timestamps: true
  utf8: true
  enable_star: true
  min_infix_len: 2
  max_matches: 1000
  mysql41: 9312
  mem_limit: 128M

在应用程序中运行搜索时出现以下错误 Sphinx 查询 (59.7ms) SELECT * FROM filodiretto_core WHERE MATCH('@filodirettotype_id 1 @site_id 1') AND sphinx_deleted = 0 ORDER BY @rank DESC LIMIT 0, 10 选项 max_matches=1000 在 126.4 毫秒内完成 500 内部服务器错误

ThinkingSphinx::SyntaxError (sphinxql: syntax error, unexpected USERVAR, expecting IDENT (or 6 other tokens) near '@rank DESC LIMIT 0, 10 OPTION max_matches=1000; SHOW META' - SELECT * FROM `filodiretto_core` WHERE MATCH('@filodirettotype_id 1 @site_id 1') AND `sphinx_deleted` = 0 ORDER BY @rank DESC LIMIT 0, 10 OPTION max_matches=1000; SHOW META):
  app/controllers/filodirettos_controller.rb:22:in `risultati'

相关的控制者声明是

    @results = @filodiretto_search.search.order('data_timestamp DESC')

管理
class FilodirettoSearch < BaseSearch
  accept :filodirettotype, :filodirettotype_id, :titolo, :domanda, :risposta, :site_id, :data, :terms
end

继承自类

class BaseSearch
  PER_PAGE = 10

  class_attribute :accepts, :base_class, :base_param, :per_page

  attr_accessor :params

  def self.accept(*accepts)
    self.accepts = accepts
    accepts += [:page]
    self.send(:attr_accessor, *accepts)
  end

  def self.set_base_class(klass)
    self.base_class = klass
  end

  def self.set_base_param(name)
    self.base_param = name.to_sym
  end

  def self.set_per_page(per_page)
    self.per_page = per_page
  end

  def base_param
    self.class.base_param ||= self.class.to_s.underscore.to_sym
  end

  def base_class
    @base_class ||= Kernel.const_get(self.class.to_s.sub('Search', ''))
  end

  def per_page
    self.class.per_page ||= PER_PAGE
  end

  def initialize(params)
    self.params = params

    self.class.accepts.each do |param|
      param_value = params[base_param][param]
      if param.to_s =~ /id/
        param_value = param_value.to_i unless param_value.blank?
      end

      instance_variable_set("@#{param}", param_value)
    end
    self.page = params[:page]
  end

  def search(options = {})
    extra_conditions = options.delete(:conditions) || {}
    order = options.delete(:order) || '@rank DESC'
    extra_with = options.delete(:with) || {}

    with = search_with.merge(extra_with)
    conditions = search_conditions.merge(extra_conditions)

    base_class.search sanitized_terms, :conditions => conditions, :with => with, :page => page, :per_page => per_page, :sort_mode => :extended, :order => order, :retry_stale => true, :match_mode => :extended
  end

  def sanitized_terms
    @terms ||= ""
    sanitize(@terms)
  end

  def sanitize(s)
    if s.respond_to? :gsub
      s.gsub("/", "\\/")
    else
      s
    end
  end

  def search_with
    with = {}
    if params[base_param][:with]
      params[base_param][:with].each do |k, v|
        with[k] = case v
        when 'true'
          true
        when 'false'
          false
        else
          v
        end
      end
    end
    with
  end

  def search_conditions
    conditions = {}
    self.class.accepts.each do |condition|
      if condition.to_s != 'terms'
        conditions[condition] = sanitize(self.send(condition)) unless self.send(condition).blank?
      end
    end
    conditions
  end
end

更新
我看到了句法方法是如何改变很多事情的。可能整个推理需要重新思考。以前我有一个 model_search 来定义接受哪些属性

  accept :filodirettotype, :filodirettotype_id, :titolo, :domanda, :risposta, :site_id, :data, :terms

这有点像 model_index 定义的重言式。
现在假设我想对 ID 和一般条款进行搜索

collection_select :filodiretto_search, :filodirettotype_id, Filodirettotype.all, :id, :name
text_field :filodiretto_search, :terms, :size => 35

filodirettotype 的 HABM 的索引位置

has filodirettotypes(:id), :as => :filodirettotype_id

似乎可以通过简洁的控制器语句使 BaseSearch 变得多余
比如:

@filodiretto_search = FilodirettoSearch.new params
@results = Filodiretto.search(params[:filodiretto_search][:terms], :with => {:filodirettotype_ids => params[:filodiretto_search][:filodirettotype_id]}) 

只有Filodiretto.search(params[:filodiretto_search][:terms]) 会生成正确的结果。但是条件语句生成:

Sphinx Query (1.0ms)  SELECT * FROM `filodiretto_core` WHERE MATCH('solare @filodirettotype_id 1') AND `sphinx_deleted`

ActionView::Template::Error (index filodiretto_core: query error: no field 'filodirettotype_ids' found in schema

我看不出该机制如何通过单个字符串标准发挥作用

更新 2 使用 HABTM 实现多元化。索引定义也需要as 符号是复数形式。

    has filodirettotypes(:id), :as => :filodirettotype_ids

并且控制器必须调用一个数组:

@results = Filodiretto.search(params[:filodiretto_search][:terms], :with => {:filodirettotype_ids => [params[:filodiretto_search][:filodirettotype_id]]}) 

不太热衷于在控制器中为值设置 if 语句 ==""
但是功能...

【问题讨论】:

    标签: ruby-on-rails-3.2 sphinx thinking-sphinx


    【解决方案1】:

    两件事应该有助于解决这个问题:

    • 您指的是 BaseSearch 的搜索方法中的 @rank - 使用较新的 SphinxQL 语法,应该是 weight()
    • 您正在调用订单方法(ActiveRecord 样式),而不是通过 :order 选项通过搜索调用传递您的自定义订单语句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-07
      • 2014-08-02
      • 1970-01-01
      • 2018-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      相关资源
      最近更新 更多