Sunspot Solr matching a single object - ruby-on-rails

I use the Sunspot gem in my RoR app to do searches on the Post model, and it works great for that. However, I need to use it's matching algorithm against a single post object.
For example, I can search all Posts like this:
Sunspot.search Post do
...
end
But, I need to do the search against a single post object, like so:
Sunspot.search #post do
...
end
Is this possible?
I want to use the same matching algorithm on a single post object to check whether it matches or it doesn't.

I don't think that's possible. It's Solr and Lucene, not Sunspot, who have all the algorithms that determine if something is a match or not for any given query. Solr clients merely construct the query parameters and feed them to Solr, then parse back Solr results.

I'm not exactly sure how to do this with sunspot, but one thing you could try is to query RSolr directly, pass in the ID of the model you want to check in the :fq, and see if it returns a result or not. Should return pretty fast because of the filter query:
solr = RSolr.connect(:url => Sunspot.session.config.solr.url)
solr.select :q => solr_query, :fq => ['type:Post', "id:#{#post.id}"]

Related

How to query a list of objects from a Rails API?

I am trying to query a list of objects from a Rails API. That is, let's say I'd like to get the instances with id 2, 4 and 7 from a certain model.
My closest guess so far has been passing a comma-separated string of ids to a regular resource/:id route, then I split the param, built an array from it and passed it to a where call.
It works - however, I feel like this is not a clean way of doing what I am aiming to do.
So I'm asking you if there's a Rails way of handling this.
How should the URL look like? How do I read the passed values from the controller?
I think that it should be a filter on index path accepting ids param.
So URL should look like
/resource?ids[]=2&ids[]=4&ids[]=7
And you can find those resources with
def index
if params[:ids].blank?
#resources = Resource.all
else
#resources = Resource.find(params[:ids])
end
end

How to add attribute/property to each record/object in an array? Rails

I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.
Here is an example of what I'm trying to do:
#news_stories.each do |individual_news_story|
#user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
individual_news_story.attributes(:author_name) = #user_for_record[0][0]
individual_news_story.attributes(:author_avatar) = #user_for_record[0][1]
end
Any ideas?
If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:
#news_stories.each do |news_story|
news_story.user.name # gives you the name of the associated user
news_story.user.profile_image_url # same for the avatar
end
To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:
NewsStory.includes(:user)... # rest of the query
If you do this, you won't need the #user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.
If you need to have those extra attributes there regardless:
You can select them as extra attributes in your NewsStory query:
NewsStory.
includes(:user).
joins(:user).
select([
NewsStory.arel_table[Arel.star],
User.arel_table[:name].as("author_name"),
User.arel_table[:profile_image_url].as("author_avatar"),
]).
where(...) # rest of the query
It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:
#news_stories.each do |individual_news_story|
user_for_record = User.find(individual_news_story.user_id)
individual_news_story.author_name = user_for_record.name
individual_news_story.author_avatar = user_for_record.profile_image_url
end
A couple of notes.
I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.
I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.
I've changed #user_for_record to user_for_record. The # denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.

How can I match a partial string to a database's object's attribute? Regexp?

I have a database containing a list of movies. A typical entry look like this:
id: 1,
title: "Manhatten and the Murderer",
year: 1928,
synopsis: 'some text...'
rating: 67,
genre_id, etc. etc.
Now I'm trying to make a series of search tests pass and so far I have made a single test case pass where if you type the title "Manhatten and the Murderer" in a text field it will find the movie that you want. The problem is with partial matching.
Now I'd like a way to search "Manhat" and match the record "Manhatten and the Murderer". I also want it to match with any movie that has "Manhat" in it. For example, it would return maybe 2 or 3 others like title: "My life in Manhattan", title: "The Big Apple in Manhattan" etc. etc.
Below is the code that I have so far in my Movie model:
def self.search(query)
# Replace this with the appropriate ActiveRecord calls...
if query =~ where(title:)
#where(title: query)
binding.pry
end
end
My question is, how can I set this up? My problem is the "where(title:) line. One thought was to use Regexp to match the title attribute. Any help would be appreciated! Thanks.
Use a query that searches a substring in between:
name = "Manhattan"
Movie.where("title like ?", "%#{name}%")
For example:
%Manhattan will get you: Love in Manhattan
Manhattan% will get: Manhattan and Company
%Manhattan% will get you both: [Love in Manhattan, Manhattan and Company]
But, if you're searching through movies synopsis, you should use Thinking Sphinx or Elastic Search
For example, with Elastic Search, you could set the synopsis like this:
Add app/indices/movie_index.rb:
ThinkingSphinx::Index.define :movie, :with => :active_record do
# fields
indexes title, :sortable => true
indexes synopsis
end
Index your data with rake ts:index
And then run Sphynx with: rake ts:start
You can search just like this:
Movie.search :conditions => {:synopsis => "Manhattan"}
Elastic Search is a great alternative to ThinkingSphinx, there's even a RailsCast about it, so you should definitely take a look to see what really suites you best... Hope this helps!
You do not need regex to find movies that have the search string. You can use SQL query like this:
Movie.where('title LIKE ?','Batman%')
That would return all movies start with "Batman"
Movie.where('title LIKE ?','%Batman%')
That would return all movies that have Batman anywhere in it's title.
I think you figured out the '%' is a joker character in the query.
One option is to run a search server alongside your Rails application. It is certainly my go to solution. This route offers a ton of features not found within Rails itself and might be overkill, but worth consideration.
I use Sphinx and implement it using the thinking-sphinx gem.
Resources:
http://pat.github.io/thinking-sphinx/
http://sphinxsearch.com/

How to search for wild card in Rails

Im trying to search my User model for all Users that start with any integer, I have code for individual letters and it works, but Im having trouble getting it working with a wild card. Right now I have this code:
in my view:
<%= link_to '#', users_charlist_path(:char => '[0123456789]' %>
and in my controller I have:
def charlist
#a = User.where('goal like ?', "#{params[:char]}%").to_a
end
how ever, '[0123456789]', doesnt seem to work as it does not return anythign to me even though I have users whose names begin with an integer. how do i do this?
The where method is a part of ActiveRecord which maps the objects to the database. So how you can query the database with a regex depends on which db you are using not on ruby. You need to look up the regex functions of the database your using. For mysql you can find them here:
http://dev.mysql.com/doc/refman/5.1/de/regexp.html
An alternative is to select all objects an use the select method to filter the results that match your needs. That method is documented here:
http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-select
On big amounts of data I whould suggest to use the database even if that means your application isnt 100% portable between different database systems.

Difficult search in ruby on rails

How can I search first in model (i know how to do this). And then search in this array for more concretence? As you see:
#articles = Article.find(:all, :conditions => { :ART_ID => #search.map(&:ARL_ART_ID)})
#a = #articles.find_all{|item| item.ART_ARTICLE_NR == search.upcase }
First i search in model, but thanks to my db) it have many wrong results, so i must to clarify my array. But there how to search like sql:
like % %
Now it search very strong: if i search AC451, it's good, but if AC45 or C451 it's nothing fetches. How to say him so that before and after
search
could be everything?
Like this, maybe?
item.ART_ARTICLE_NR.include?(search.upcase)
You are asking for trouble by not following rails naming conventions an using upper case column names. That said, the rails3 way to do it is probably:
#articles = Article.where(:ART_ID => #search.map(&:ARL_ART_ID)).where('ART_ARTICLE_NR LIKE', "%#{search.upcase}%")
Without knowing what #search is, it's hard to be sure. But you should read up on the active record guide on the rails 3 query format.
It's maybe not straigtforward answer, but have you considered using ransack gem?

Resources