I need thinking_sphinx query to retrieve "begins_with" values.
means if I give Student.search 'a', I want to display all student who have name starts with a.
I have indexed the name field already.Now, to retrieve a student, I have to give the exact name.
Sounds like you want wildcard searches. Either add this to your config/sphinx.yml file - or create it if you don't already have one:
development:
enable_star: 1
min_prefix_len: 1
# repeat for other environments
Or you can put it in a specific index - as infix/prefix settings increase the size of your indices dramatically:
define_index do
# ...
set_property :enable_star => 1
set_property :min_prefix_len => 1
end
And then, run rake ts:rebuild so the changes are known by Sphinx and processed in the indices, and then you can search like this:
Student.search 'a*'
# or
Student.search :conditions => {:name => 'a*'}
And if you use min_infix_len instead of min_prefix_len, you can match within words as well - that is, put the star on either side:
Student.search '*a*'
Finally - if you always want your queries to have wildcard stars on each end of every term, use :star => true in your searches:
Student.search 'a b c', :star => true
# is the same as
Student.search '*a* *b* *c*'
Hope this helps you get the result you're looking for :)
Related
I have two models: 'A' and 'B', and want to search objects from both of them using Thinking sphinx, but I want all results of model 'A' first and then 'B'. How can I do that?
I pass the following options to sphinx query
{:match_mode=>:extended, :sort_mode=>:extended, :star=>true, :order=>"#relevance DESC", :ignore_errors=>true, :populate=>true, :per_page=>10, :retry_stale=>true, :classes => [A,B]}
And then get search results using:
ThinkingSphinx.search "*xy*", options
But it gives results in mixed ordering, whereas I need all 'A' objects first. How can I do that?
The easiest way is to add an attribute to both models' indices:
has "1", :as => :sort_order, :type => :integer
The number within the string should be different per model. And then your :order argument becomes:
:order => 'sort_order ASC, #relevance DESC'
In my Ruby on Rails application I have a database structure like this:
Project.create(:group => "1", :date => "2014-01-01")
Project.create(:group => "1", :date => "2014-01-02")
Project.create(:group => "1", :date => "2014-01-03")
Project.create(:group => "2", :date => "2014-01-01")
Project.create(:group => "2", :date => "2014-01-02")
Project.create(:group => "2", :date => "2014-01-03")
# and so forth...
How can I get the latest record from each group using ActiveRecord?
The solution is probably simple but I can't get my head around this.
Thanks for any help.
Postgres
In Postgres, this can be achieved with the following query.
SELECT DISTINCT ON ("group") * FROM projects
ORDER BY "group", date DESC, id DESC
Because the date column might not be unique here, I have added an additional ORDER BY clause on id DESC to break ties in favor of the record with the higher ID, in case two records in a group have the same date. You might instead want to use another column like the date/time of the last update or so, that depends on your use case.
Moving on, ActiveRecord unfortunately has no API for DISTINCT ON, but we can still use plain SQL with select:
Project.select('DISTINCT ON ("group") *').order(:group, date: :desc, id: :desc)
or if you prefer using ARel instead of having raw SQL:
p = Project.arel_table
Project.find_by_sql(
p.project(p[Arel.star])
.distinct_on(p[:group])
.order(p[:group], p[:date].desc, p[:id].desc)
)
MySQL
For other databases like MySQL this is unfortunately not as convenient. There are a variety of solutions available, see for example this answer.
I spent some time battling this and thought I'd share what I found to be the cleanest and stunningly easy solution (assuming date or other sorting field contains unique values):
Project.group(:group).maximum(:date)
Hat tip to qarol for posting this in this comment.
This works for me
ids = Message.select("MAX(id) AS id").group(:column_name).collect(&:id)
#result = Message.order("created_at DESC").where(:id => ids)
Following solution based on this link works for MySQL and it's extensible to all fields in group table.
Project.select(:group, 'MAX(date) AS date').group(:group)
Something like this?
Project.select(:group).map(&:group).uniq.each do |grp|
puts Project.where(group: grp).order("date DESC").last
end
This will go through all your groups and identify the unique ones. In your example it should return ["1", "2"]. Then it iterates over that array and selects the last Project with a group id of 1 and the last Project with a group id of 2.
** Update **
Just realized you said "latest" and not "last" which required adding an order to ensure latest works. Last still pulls just one.
Project.where(:group => "1", :date => "2014-01-01").last
.last is what you are looking for.
I am facing problem in thinking sphinx
What i have following table structure
title => varchar
desc => varchar
is_deleted => boolean
Here is my denine_index
define_index do
indexes title, :sortable => :insensitive
has :is_deleted, :type=>:boolean
where "is_deleted = false"
set_property :delta => true
end
Here when I edit the topic and search it with edited name, I get the topic and when I search it with old name I get the same topic. For eg if earlier topic had name "Foo" and I renamed "Foo" to "Woo", on searching "Woo" I get "Woo", but on searching "Foo", I again get "Woo". Moreover when I set is_deleted => true and search "Woo" I don't get anything, but on searching "Foo" again I get "Woo". I can't understand why it is happening? Does sphinx don't delete the older index on creating newer index for delta=true.
Again on rebuilding sphinx, i don't get such problems, and all delta is set to false as expected.
Use sphinx sql_query_killist to kill results from main index when you know it exists in your delta index similar to these: http://sphinxsearch.com/docs/1.10/conf-sql-query-killlist.html
I have model Products with columns:
name, number, description
Index defined for this model looks like this:
define_index do
indexes :name, :sortable => true
indexes :number
indexes :description
where "amount > 0"
has :price
end
Since in description can be lots of random words I want to exclude it from searching sometimes (when user clicks chceckbox 'don't search in descriptions').
I went to the sphinx page and found following:
#(name, number) *pencil* *123*
And it seems like I don't understand how sphinx works. When I execute search
*pencil* *123*
word 'pencil' is found in name and '123' is found in number and I get 1 result. But when I execute
#(name, number) *pencil* *123*
no results are found.
Is searching by columns somehow different?
You can only search on fields when using the :extended match mode - Thinking Sphinx sets this automatically if you use :conditions - but you're constructing a multi-field query yourself, hence why this isn't happening. Try this:
Product.search "#(name, number) *pencil* *123*", :match_mode => :extended
Hope this helps.
It was all about spaces :/
This works:
#(name,number) *pencil* *123*
I have a record set that includes a date field, and want to determine how many unique dates are represented in the record set.
Something like:
Record.find(:all).date.unique.count
but of course, that doesn't seem to work.
This has changed slightly in rails 4 and above :distinct => true is now deprecated. Use:
Record.distinct.count('date')
Or if you want the date and the number:
Record.group(:date).distinct.count(:date)
What you're going for is the following SQL:
SELECT COUNT(DISTINCT date) FROM records
ActiveRecord has this built in:
Record.count('date', :distinct => true)
Outside of SQL:
Record.find(:all).group_by(&:date).count
ActiveSupport's Enumerable#group_by is indispensable.
the latest #count on rails source code only accept 1 parameter.
see: http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-count
so I achieved the requirement by
Record.count('DISTINCT date')
Detailing the answer:
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 2, :created_on => '2010-09-29')
Post.create(:user_id => null, :created_on => '2010-09-29')
Post.group(:created_on).count
# => {'2010-09-29' => 4}
Post.group(:created_on).count(:user_id)
# => {'2010-09-29' => 3}
Post.group(:created_on).count(:user_id, :distinct => true) # Rails <= 3
Post.group(:created_on).distinct.count(:user_id) # Rails = 4
# => {'2010-09-29' => 2}
As I mentioned here, in Rails 4, using (...).uniq.count(:user_id) as mentioned in other answers (for this question and elsewhere on SO) will actually lead to an extra DISTINCT being in the query:
SELECT DISTINCT COUNT(DISTINCT user_id) FROM ...
What we actually have to do is use a SQL string ourselves:
(...).count("DISTINCT user_id")
Which gives us:
SELECT COUNT(DISTINCT user_id) FROM ...
Also, make sure you have an index on the field in your db, or else that query will quickly become sloooow.
(It's much better to do this in SQL, otherwise you pull the entire db table into memory just to answer the count.)