Date range facets with Sunspot in Ruby on Rails - ruby-on-rails

I am using Sunspot to search for events (parties, concerts, ...) in a Ruby on Rails 3 application.
I have managed to set up free text search and facet search on a couple of different category types.
Now, I am stuck with my next task. I want to set up facets related to when the event is occuring.
I want to have facets describing both relative date/time ranges such as "today", "this weekend", "next weekend" and absolute date/time ranges, such as "Easter Holiday 2011", "New Years Day 2012", ... The datetime ranges are sometimes overlapping each other.
I have browsed around in the Sunspot API documentation, the Sunspot wiki, here at Stackoverflow, read and loads of articles and blogs. People are writing it is possible to to achieve but I find no examples or implementation ideas that makes me understand how to do this.
Any suggestions?
Since my problem is not in my code, I don't publish any code. The class Event has a DateTime instance named "start_time". I do understand it's my job to define when the absolute date/time ranges appear in the calender.
Best regards,
./stefan
PS Did I tell I'm a newbie? ;-) DS

You should set up your fields as trie time fields for efficient range queries:
class Event
searchable do
time :start_time, :trie => true
end
end
Then you can use query facets to facet based on ranges:
Event.search do
facet :start_time do
bod = Time.zone.now.beginning_of_day
row :today do
with :start_time, bod..(bod + 1)
end
row :tomorrow do
with :start_time, (bod + 1)..(bod + 2)
end
# etc.
end
end
The key insight here is that you can construct facets using arbitrary scopes. Note that the facet name :start_time is just used to reference the facet in the search results, and the row labels :today and :tomorrow are similarly just used on the client side to identify the row counts corresponding to those queries; they have no meaning from Solr's standpoint, so you can call them whatever you want (using whatever data type you want -- they don't have to be symbols).
More information on query facets here: http://sunspot.github.com/docs/Sunspot/DSL/FieldQuery.html#facet-instance_method

You can do in this way:
with(:registration_date).between(params[:start_date].to_date..params[:end_date].to_date)
Look here: http://sunspot.github.io/docs/Sunspot.html#search-class_method

Related

How to use Rails to efficiently find only recent rows in a large table

I have a 10,000+ row table that I am trying to query in Rails 4. Let's call it events and there are many, many years of past events still in the database. I need to grab only the events with a date of today or in the future. I could do something like:
#events = Event.where('date >= ?', todays_date)
but this still takes a long time as it has to go through every record. Is there a simple way to speed this up? I've even considered that starting from the most recent rows, moving backwards, and limiting to say 1,000 total would be "good enough", although it could potentially leave out an event created a long time ago but with a date in the near future. I'm not even sure how to go about starting from the last row, however. And I feel like there has to be a better solution anyhow.
Any ideas? Thank you in advance!
One thing you can do to speed up the search is to add index to the created_at field (or to the custom date field you are using). Index makes the searching process faster in the database.
You can refer this answer to add index.
It sounds like adding an index to your date column could help with efficiency here.
Migration code below:
class AddIndexToEvents < ActiveRecord::Migration
def change
add_index :events, :date
end
end

How to find certain range of values from the results of find_by method

I have an attribute rank in a table whose values range from 1-100. I would like to perform facet search on it by providing options to a range of rank values such as 1-5, 6-10 etc.
I currently have the following code in my view file
<%= link_to_unless_current Univ.find(facet['term']).rank, params.merge(id: facet['term']) %>
which seperately displays the values.
Is there a way that I could perform a range search on the attribute?
Please help
Try to check the following question which implements facet by using Searchkik
Setting up Facets in Elasticsearch with Searchkick gem in Rails 4.1
Hope that gives you an idea to implement using tire
You can use a Rnage within where values:
Model.where(value: 1..5)
If you for example need values to be in range 1-20 or 45-70, youc an wrap them in array:
Model.where(value: [1..20, 45..70])

Ruby on Rails: How to create a class schedule calendar with hour by hour breakdown?

I'm a new ruby on rails coder who is trying to create a neatly displayed calendar of the week for students to check their timetables.
I have stored the lessons in a table with the following data:
:course_id, :state_unit_code, :day_of_week, :start_date, :end_date, :start_time, :end_time, :classroom_id, :campus_id, :lecturer_id
I wish to take the data from that table and transform it into an html table similar to that shown:
I've mocked it up using table, tr td rowspan colspan and so on.
If you can point me in the right direction I'd be most appreciable.
Follows on from a post by another user (allesklar): How would you build this daily class schedule?
I would recommend using a gem for this unless you are a strong confident rails programmer with some decent experience. It's a good project if you're just doing it to learn but not so much if you actually want it to be used as a 'production app. in the real world.
I think that https://github.com/elevation/event_calendar might meet your needs. Take a look and see.
You may also need to use a separate gui date picker at some point and their are many solutions for that such as http://code.google.com/p/calendardateselect/ though this is just about picking dates, not the full calendar display of event also. But it could be handy. You'll also see 30 (!) different date pickers here: http://www.1stwebdesigner.com/freebies/jquery-calendar-plugins/ that also include ones that let you span dates.

Comparing two dates for past or not in rails 3.1 app

In my ruby(1.9.3) on rails (3.1) app I'm trying to set some conditional behavior with respect to tasks and deadlines. Specifically the coloring of a progress bar.
Tasks belongs_to list
List has_many tasks
I'm essentialy trying to see if the last task.planned_for date in #list.tasks is past #list.deadline.
Both list.deadline and task.planned_for are :date types.
So in my view I'm looking for something like:
- if #last_task.planned_for > #list.deadline
Where
#tasks = #list.tasks.todo
#last_task = #tasks.last
Any ideas on how to best do this. This (obviously) isn't working.
Your #tasks.last doesn't grab the latest one, it grabs the last one in the database, not in any particular order. You probably want to get it with
#last_task = #list.tasks.order('planned_for DESC').first`
(by ordering it descending, the first date is latest)

How do you store recurring time periods on a database? Like "from the first of january to the last day of may"?

I have to store recurring date periods, similar to the one in the title, and I have no idea if there is an optimal day to do this. The first solution I came up with was to have day and month fields for start and end dates, but this solution doesnt sound very right to me.
I am using Ruby on Rails with SQL.
To store recurring dates of arbitrary complexity, you want to look into temporal expressions.
Some gems available are: runt, TExp or icecube
I've used both runt and icecube, as well as storing recurring dates (weekly schedules) in serialized ruby objects. The gems are the most flexible, if a little hard to use when your use case is simple.
Also if you need to parse textual expersions, look at Chronic
In ruby, you could probably express this nicely (for a particular year) with a Range:
(Time.utc(2012, 1, 1)..Time.utc(2012, 5, 1).end_of_month)
But storing this in a database...can only think of doing what you said (columns for start/end day and month), and then adding wrapper methods on the model similar to this:
def current_start
Time.utc(current_year, start_month, start_day)
end
...
def current_range
(current_start..current_end)
end
I would just use two dates... afaik that maps nicely to ruby Date objects anyway, with which you can do the usual arithmetic.

Resources