If have multiple indexed models that have a verification level which need to be sorted by their verification level.
But I also have a couple of models without a verification level.
ThinkingSphinx.search #search.q, :order => 'class_crc ASC, #relevance DESC, verification_level DESC', :page => page, :limit => limit, :classes => #search.types_as_models
The problem is I can rank by verification_level on models that have that attribute but it errors on models without a verification_level
index ground_core,ground_delta,user_core,user_delta: sort-by attribute 'verification_level' not found
Example player define_index with verification_level
define_index do
indexes [first_name, last_name], :as => :name, :sortable => true
where "state = 1"
has created_at, updated_at, verification_level
set_property :delta => ThinkingSphinx::Deltas::ResqueDelta
end
Example User define_index without verification_level
define_index do
indexes [first_name, last_name], :as => :name, :sortable => true
has created_at, updated_at
set_property :delta => ThinkingSphinx::Deltas::ResqueDelta
end
Is there a way to sort when it is on a model and ignore when it isnt?
My solution was to fake a verification level on models which didn't require it by adding it in the define_index block
has '0', :as => :verification_level, :type => :integer
Related
Calling all elasticsearch experts:
Environment:
elasticsearch (6.8.3)
rails 5.1.7
Linux
We changed our association from our user model to the person model from a has_one to a has_many. We did not however remove the person_id column as this can cause other issues (e.g. running code from another branch that still tries to use it)
It seems no matter what we do to the index definitions for ElasticSearch, if any null values exist in person_id (which they do now with all newly added records) we get
"No value specified for terms query"
I have confirmed this by populating that column with an integer value resulting in no error occurring.
I have removed person_id from any indexes I even removed any reference to the peoples table in the ES index declaration but it appears that as soon as ES sees there is an association to a Person model and it sees the person_id column, it tries to use it.
Besides writing an arbitrary value in the person_id column, does anyone else have a better approach? We DO NEED to search fields in the associated Person model (peoples table) but since it's a has_many, it shouldn't be using the person_id column which is no longer relevant.
We also considered reversing the search from Person to User but that would require a LOT of recoding.
Is it possible a newer version of ES will fix it? We'd probably have to upgrade the ES server as well if we update the gem right?
Here is the association:
has_many :people, :class_name => Person.to_s # I believe it's this class name that's causting it to try to use the person_id column
Here is the index definition
def as_indexed_json(_options = {})
as_json(
:only => %i[id email portal_id],
:include => {
:portal => { :only => %i[name slug] },
:people => { :methods => %i[first last full_name], :only => %i[first last full_name] },
:events => { :only => [:id] },
:account_brokerage_firms => { :only => [:id] },
:brokerage_firms => { :only => [:id] },
:roles => { :methods => [:role_name], :only => [:role_name] }
}
)
end
settings AUTOCOMPLETE_SETTINGS do
mapping :dynamic => 'false' do
indexes :id, :type => 'long'
indexes :email, :type => 'text', :analyzer => 'email'
indexes :portal_id, :type => 'long'
indexes :people do
indexes :first, :type => 'text', :analyzer => 'autocomplete'
indexes :last, :type => 'text', :analyzer => 'autocomplete'
indexes :full_name, :type => 'text', :analyzer => 'autocomplete'
end
indexes :portal do
indexes :name, :type => 'text', :analyzer => 'autocomplete'
indexes :slug, :type => 'text', :analyzer => 'autocomplete'
end
indexes :events do
indexes :id, :type => 'long'
end
indexes :account_brokerage_firms do
indexes :id, :type => 'long'
end
indexes :brokerage_firms do
indexes :id, :type => 'long'
end
indexes :roles do
indexes :role_name, :type => 'text', :analyzer => 'autocomplete'
end
end
end
# end of elastic search settings
# this function assumes there is only one user role between a user and an account
I am experiencing some issues with Thinking Sphinx not allowing me to search by the deleted_at column in my database.
Essentially, I would like to get a list of all users, active users and deleted users, then be able to undelete certain users defined by the admin. Unfortunately, I can't even list the deleted users when using Thinking Sphinx. When I do a regular search for all users where 'deleted_at IS NOT NULL', I can get the users.
I can do any other field in my index just fine, but not deleted_at. Each time, I get this:
ERROR -- : index user_core: no such filter attribute 'deleted_at' (ThinkingSphinx::SphinxError)
This is my index file:
ThinkingSphinx::Index.define :user, :with => :active_record, :delta => true do
indexes first_name, :sortable => true
indexes last_name, :sortable => true
indexes email, :sortable => true
indexes phone, :sortable => true
has deleted_at, :as => :deleted
has id, :as => :user_id
has roles(:id), :as => :role_ids
set_property :delta => true
end
And my query:
params[:with][:deleted_at] = 0
#results = User.search :conditions => params[:conditions], :with => params[:with],
:order => params[:sort] + ' ' + params[:sort_mode], :page => params[:page],
:per_page => params[:per_page], :star => true
NOTE: Even if I do just #results = User.search, I still get a list of only all active users where deleted_at is null. I do not seem to be able to get all users when using Thinking Sphinx.
I use thinking_sphinx for search, and i'm trying to get the output table in which fields are grouped according to weight(from set_property :field_weights)
This define_block
define_index do
indexes status, title, content, manager, note, start_date, end_date
has created_at, updated_at, parent_id, organization_id
has user_id, :as => :user_id, :type => :integer
has '7', :as => :model_order, :type => :integer
set_property :field_weights => {
:title => 1,
:start_date => 2,
:user_id => 7
}
set_property :delta => true
end
How to sort the field (in the template) depending on their weight?
I'm not sure if I understand the Q, but it seems that you are trying to read the configuration of the field_weights from the view...
I don't know if thinking_sphinx has a method to do that, but what I would do is save that configuration elsewere and use it where you need it...
class YourModel
FieldWeights = {
:title => 1,
:start_date => 2,
:user_id => 7
}
# more code here....
define_index do
indexes status, title, content, manager, note, start_date, end_date
has created_at, updated_at, parent_id, organization_id
has user_id, :as => :user_id, :type => :integer
has '7', :as => :model_order, :type => :integer
set_property :field_weights => YourModel::FieldWeights
set_property :delta => true
end
end
Then in your view you can use YourModel::FieldWeights to display the fields in order of their weights, for example:
YourModel::FieldWeight.invert.sort
I have 2 models User and Discussion. I have defined the indices for the models as below:
For the User model:
define_index do
indexes email
indexes first_name
indexes last_name, :sortable => true
indexes groups(:name), :as => :group_names
has "IF(email_confirmed = true and status = 'approved', true, false)", :as => :approved_user, :type => :boolean
has "IF(email_confirmed = true and (status = 'approved' or status='blocked'), true, false)", :as => :approved_or_blocked_user, :type => :boolean
has points, :type => :integer
has created_at, :type => :datetime
has user(:id)
set_property :delta => true
end
For the Discussion model:
define_index do
indexes title
indexes description
indexes category(:title), :as => :category_title
indexes tags(:title), :as => :tag_title
has "IF(publish_to_blog = true AND sticky = false, true, false)", :as => :publish_to_main, :type => :boolean
has created_at
has updated_at, :type => :datetime
has recent_activity_at, :type => :datetime
has views_count, :type => :integer
has featured
has publish_to_blog
has sticky
set_property :delta => true
end
I have added a delta column to both tables as per the documentation. My problem is that delta indexing works only for the Discussion model and not for the User model. For ex: When I update the 'title' of a discussion, I can see the thinking sphinx is rotating the indices etc. (as is evident from the logs). But when I update the 'first_name' or the 'last_name' of a user, nothing happens.
The User model also has a has_many :through association through a model called GroupsUser. I have setup a after_save on the GroupsUser as follows:
def set_user_delta_flag
user.delta = true
user.save
end
Even this doesn't seem to trigger delta indexing on the User model. A similar setup for the Discussion model works perfectly! Can anyone tell me why this is happening?
Alright I figured it out. The problem was with the attribute definition:
has user(:id)
When I removed it from the definition and ran a rebuild, everything seemed to work perfectly.
I installed Sphinx and Thinking Sphinx for ruby on rails 2.3.2.
When I search without conditions search works ok. Now, what I'd like to do is filter by tags, so, as I'm using the acts_as_taggable_on plugin, my Announcement model looks like this:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
define_index do
indexes title, :as => :title, :sortable => true
indexes description, :as => :description, :sortable => true
indexes tags.name, :as => :tags
indexes category.name, :as => :category
has category(:id), :as => :category_ids
has tags(:id), :as => :tag_ids
end
For some reason, when I run the following command, it will bring just one announcement, that has nothing to do with what I expect. I've got many announcements, so I expected a lot of results instead.
Announcement.search params[:announcement][:search].to_s, :with => {:tag_ids => 1}, :page => params[:page], :per_page => 10
I guess something is wrong, and it's not searching correctly.
Can anyone give my a clue of what's going on?
Thanks,
Brian
Thinking Sphinx relies on associations in model. In common situations you only have to put index definition below your associations.
With acts_as_taggable_on plug-in you don't have tag-related associations in model file and when you write
indexes tags.name, :as => :tags
TS interprets it like:
CAST(`announcements`.`name` AS CHAR) AS `tags`
(look at sql_query in development.sphinx.conf, in my case).
I suppose that you have attribute name in model Announcement and don't run into error when rebuild index.
But we expect:
CAST(GROUP_CONCAT(DISTINCT IFNULL(`tags`.`name`, '0') SEPARATOR ' ') AS CHAR) AS `tags`
and:
LEFT OUTER JOIN `taggings` ON (`announcements`.`id` = `taggings`.`taggable_id`)
LEFT OUTER JOIN `tags` ON (`tags`.`id` = `taggings`.`tag_id`) AND taggings.taggable_type = 'Announcement'
To get things working just add tag-related associations in your model before you rebuild index:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
:conditions => "taggings.taggable_type = 'Announcement'"
#for context-dependent tags:
has_many :category_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag",
:conditions => "taggings.context = 'categories'"
In define_index method:
indexes category_tags(:name), :as => :tags
has category_tags(:id), :as => :tag_ids, :facet => true
In controller:
#announcement_facets = Announcement.facets params[:search], :with => {:tag_ids => [...]}
#announcements = #announcement_facets.for.paginate( :page => params[:page], :per_page => 10 )
I found that simply defining the index thus:
Class Thing < ActiveRecord::Base
acts_as_taggable
define_index do
..other indexing...
indexes taggings.tag.name, :as => :tags
end
end
worked fine.
One possibility is that you need to declare the type for tag_ids as :multi because TS can get confused (I just discovered this here http://groups.google.com/group/thinking-sphinx/browse_thread/thread/9bd4572398f35712/14d4c1503f5959a9?lnk=gst&q=yanowitz#14d4c1503f5959a9).
But why not use the tag names to search? E.g.,
Announcement.search params[:announcement][:search].to_s, :conditions => {:tags => "my_tag"}, :page => params[:page], :per_page => 10
Or, if you need to search for multiple tags:
Announcement.search( "#{params[:announcement][:search].to_s} (#tags my_tag | #tags your_tag)", :page => params[:page], :per_page => 10 )
(as aside, you may want to sanitize/remove sphinx-control-characters from the user-provided query before using it).
For debugging, I would go into console and strip down your query as much as possible (eliminate pagination arguments, even the query (just do ""), etc.).