Searching multiple columns with Sphinx - ruby-on-rails

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*

Related

Indexing using two tables in sunspot solr + rails 4

I'm using sunspot-solr in ROR and I need help in creating a searchable block using two tables.(join of two tables)
The query I want to be executed when the indexes are formed is :
SELECT a.id,a.title
FROM table_one a,table_two b
WHERE a.status=1
AND a.id=b.id
AND b.status=1
I want the "title" field to be searchable(text), only if the id exists in both tables and both have status 1.And I want them to be stored fields(no db hits).
class TableOne
has_many :table_twos
searchable do
text :title, :stored => true
string :status, :stored => true
string :id, :multiple => true, :stored => true do
table_twos.map(&:id)
end
end
When I searched a word, I got 5 results.
But when I delete an entry of one of the results from table_two and searched the same word again.. I still got 5 results when I should get only the other 4.
Any help ?
If you delete an associated record that was stored as a solr/sunspot record, you will have no choice but to reindex that record.
So to solve the issue I did somthing like without(:id,nil) in my controller and I got the results as I wanted them.
I'm not sure its the right way to go about it though.

Sunspot: boost elements when match a multiple values field

I have an object Foo which has many objects Bee.
class Foo
has_many :bees
I index my object A with Sunspot SOLR like this.
searchable do
text :title, boost: 5
text :content, boost: 2
integer :bee_ids, multiple: true
...
end
to keep track of Bee ids related to my Foo object.
Now I have a User that performs searches on Foos objects. The User has many Bees too.
class User
has_many :bees
...
end
When I search Foos objects I would like to boost objects which have bees that matches User's bees.
Foo.search do
fulltext query
any_of do
...
with(:bee_ids, #user.bees.pluck(:id))
end
end
I want to give priorities to objects that matches user's interests. Any idea?
Well. I found a solution for the problem above.
You need to use bq parameter to do that and give a boost to that condition.
I added
adjust_solr_params do |params|
params[:bq] = " bee_ids_im:(#{#user.bees.pluck(:id).join(' OR ')})^20"
end
and I give a boost to the above condition of 20 times.
Actually that the solution to the more generic problem of giving boost to specific conditions in the query.
Sunspot support boost queries with boost command.
So I changed my query with:
Foo.search do
fulltext query do
boost(20.0) do
with(:bee_ids, #user.bees.pluck(:id))
end
end
any_of do
...
with(:bee_ids, #user.bees.pluck(:id))
end
end
and I obtained the same result.
Hope this can help someone else.

Thinking Sphinx search using 'with' and indexed attributes

UPDATE:
Ok so I am no longer getting an error, but I am not getting any results back (even when there is only one search option).
I added the has clause to my list of indexes:
define_index do
has bar_profiles(:day), :as => :days
indexes bar_profiles.budget, :as => :budget_tags
.
.
end
So my search is:
bars = Bar.search(search_options)
with
search_options = {:conditions=>{:budget_tags=>"LOW BUDGET"}, :with=>{:days=>"thursday"}, :page=>1, :per_page=>20}
bar_profiles has rows for budget, experience, tags, day, etc.
Bar has many bar_profiles (potentially 1 for each day)
What I am trying to do is use the thinking sphinx search (in the bar model) to match the users selected criteria for budget, experience, tags against the bar_profile that has the day that matches with "today" (the current day).
This is the last thing I have to do to finish this app and I'm pulling my hair out cause I can't find any examples of how to set this up right...
If you have any insight please post it, anything helps. Thanks.
At first I thought my question was similar to this with an extra layer of abstraction, but I think my problem is with the search options not the indexing.
First off let me state that I have been having the worse time trying to fix a previous' groups implementation using thinking sphinx. I have finally got the project 90% working and the last 10% deals with being able to get the right filters to check against.
Here is a brief overview. The application has bars and bar_profiles (amongst many other tables that connect to these 2, and users, but they are not necessary to understand this issue.) There can be a bar_profile for each day of the week, for each bar.
So in the bar_profile model there is:
belongs_to :bar
and in bar there is:
has_many :bar_profiles
followed by the indexes in bar (written by the previous developer):
define_index do
# name is a reserved keyword so we need to specify it as a symbol to work
indexes :name
indexes tags
indexes bar_profiles.day, :as => :day
indexes bar_profiles.tags, :as => :daily_tags
indexes bar_profiles.budget, :as => :budget_tags
indexes bar_profiles.experience, :as => :experience_tags
set_property :delta => true
end
The issue I am having is this current implementation does not constrain the search properly to the current day. Instead of checking the current days profile for the bar, it seems to be checking against ALL the bars profiles.
So I set the current day at the start of the method:
today = (Time.now + Time.zone_offset('EST')).strftime("%A")
Then I think it needs to be something like below. I referenced this post by pat about using 'with', but I am not sure if I am messing up the syntax (because I am getting an error):
search_options = {:conditions => {}, :with => {:day=>today}, :page => 1, :per_page => algorithm.results_per_page}
Then I use these search options:
search_options[:conditions][:experience_tags] = options[:experience] unless options[:experience].blank?
budget = combine_budgets(options[:budget])
search_options[:conditions][:budget_tags] = budget unless budget.blank?
But when I try to run the search I get this in my development log:
^^^^ ERROR! Reason: index bar_core,bar_delta: no such filter attribute 'day'
Now I am pretty confused by this since the index for :day was set up as shown above... I'm not sure if 'filter attribute' is different then an index attribute. If someone could please offer some insight into this it would be greatly appreciated (looking at you #pat).
This is the final issue in this app, so if anyone can help me I would be very grateful.
Thanks,
Alan

Thinking sphinx not reindexing for delta=true

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

Searching with thinking_sphinx and filtering results

I have this scenario where I thought it would be pretty basic, but found out that I can't really achieve what I need. This is why I have this question for a thinking_sphinx's expert.
The scenario is this: I need do a search within a list of companies and only return those who has an address (there can be many address by company) which belongs to a particular city or none at all (this I can do).
I have the following models :
class Company < ActiveRecord::Base
has_many :company_addresses
define_index
indexes :name
indexes :description
indexes :keywords
end
end
and
class CompanyAddress < ActiveRecord::Base
end
The CompanyAddress has a city_id property. Without looping through all returned records from a sphinx search, is there a way to achieve the same thing more easily?
I'm using Rails 3.0.3 and thinking_sphinx.
You'll want to add an attribute pointing to the city_id values for the company:
has company_addresses.city_id, :as => :city_ids
And then you can filter on Companies belonging to a specific city:
Company.search 'foo', :with => {:city_ids => #city.id}
If you want both matching to a specific city or has no cities, that's a little trickier, as OR logic for attribute filters is more than a little tricky at best. Ideally what you want is a single attribute that contains either 0, or all city ids. Doing this depends on your database, as MySQL and Postgres functions vary.
As a rough idea, though - this might work in MySQL:
has "IF(COUNT(city_id) = 0, '0', GROUP_CONCAT(city_id SEPARATOR ',')",
:as => :city_ids, :type => :multi
Postgres is reasonably similar, though you may need to use a CASE statement instead of IF, and you'll definitely want to use a couple of functions for the group concatenation:
array_to_string(array_accum(city_id, '0')), ',')
(array_accum is provided by Thinking Sphinx, as there was no direct equivalent of GROUP_CONCAT in PostgreSQL).
Anyway, if you need this approach, and get the SQL all figured out, then your query looks something like:
Company.search 'foo', :with => {:city_ids => [0, #city.id]}
This will match on either 0 (representing no cities), or the specific city.
Finally: if you don't reference the company_addresses association anywhere in your normal fields and attributes, you'll need to force to join in your define_index:
join company_addresses
Hopefully that provides enough clues - feel free to continue the discussion here or on the Google Group.

Resources