Filter issue with tire elasticsearch - ruby-on-rails

Want to search for the title from the board with live_flag true.
class Board < ActiveRecord::Base
has_many :deals
include Tire::Model::Search
tire.mapping do
indexes :title, type: 'string'
indexes :deals do
indexes :title, type: 'string'
end
end
def to_indexed_json
{
:title => title,
:deals => {:title => self.deals.map(&:title)},
}.to_json
end
def self.search(params)
tire.search(load: true) do
query {string params[:query]+"*"}
filter :term, live_flag: true
sort { by :created_at, "desc" } if params[:query].blank?
end
end
end
Now it will not search anything.
It works properly when below code is used. Difference is that i have removed filter text from it.
def self.search(params)
tire.search(load: true) do
query {string params[:query]+"*"}
sort { by :created_at, "desc" } if params[:query].blank?
end
end
**But i want to get boards whose live_flag is true.**

Right now your index does not include the live_flag
just add live_flag to your to_indexed_json and mapping
tire.mapping do
indexes :title, type: 'string'
indexes :live_flag, type: 'boolean'
indexes :deals do
indexes :title, type: 'string'
end
end
def to_indexed_json
{
:title => title,
:live_flag => live_flag,
:deals => {:title => self.deals.map(&:title)},
}.to_json
end

Related

Solr search multiple fields including field association

I have the following classes:
class User < ActiveRecord::Base
searchable do
text :full_name, boost: 3.0
text :about_me
join(:name, target: Nickname, type: :text, join: { from: :user_id, to: :id })
end
end
class Nickname < ActiveRecord::Base
searchable do
text :name
integer :user_id
end
end
What I would like to do is to search for a user by its full_name, about_me or has a nickname with the searched email.
I tried the following and I never get a result:
User.search { fulltext 'FrodoBaggings' }.results
User.search { fulltext 'FrodoBaggings'; fulltext 'Frodo', fields: [:name] }
User.search do
any do
fulltext 'Frodo Baggings', fields: [:full_name, :about_me]
fulltext 'Frodo Baggings', fields: [:name]
end
end

Search multiple models with Tire and ElasticSearch

I have two models, Posts and Channels that I'm searching using Tire and ElasticSearch.
Currently, everything works just fine. However, I'm performing two searches and returning the results of both. I'd like to consolidate this into one – and search both models at the same time.
Below is the controller action I'm using to do just this:
def browse
#user = current_user
#channels = Channel.search(params)
#posts = Post.search(params)
end
Below is the Post model:
class Post < ActiveRecord::Base
attr_accessible :description, :name, :tag_list, :thumbnail_image, :status, :post_type, :subtitle, :summary, :visibility, :user
acts_as_taggable
has_one :publication
has_one :user, :through => :publication
has_many :subscriptions, dependent: :destroy
has_many :channel_post_connections, dependent: :destroy
has_many :channels, :through => :channel_post_connections
accepts_nested_attributes_for :channel_post_connections
accepts_nested_attributes_for :channels
accepts_nested_attributes_for :publication
accepts_nested_attributes_for :user
has_many :post_pages, dependent: :destroy
validates_presence_of :post_type, :name, :subtitle, :tag_list, :summary, :thumbnail_image, :if => :post_is_published?
include Tire::Model::Search
include Tire::Model::Callbacks
index_name 'posts_index'
def self.search(params)
tire.search(load: true) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
sort { by :created_at, "desc" } if params[:query].blank?
end
end
def to_indexed_json
to_json(methods: [:user_first_name, :user_display_name])
end
def user_first_name
self.user.first_name if self.user.present?
end
def user_display_name
self.user.display_name if self.user.present?
end
end
Below is the Channel model:
class Channel < ActiveRecord::Base
attr_accessible :title, :description, :cover_image, :status, :writable, :visibility, :thumbnail_image
has_one :channel_publication
has_one :user, :through => :channel_publication
has_many :channel_subscriptions
has_many :channel_post_connections
accepts_nested_attributes_for :channel_publication
accepts_nested_attributes_for :user
mount_uploader :thumbnail_image, ChannelThumbnailImageUploader
include Tire::Model::Search
include Tire::Model::Callbacks
index_name 'channels_index'
def self.search(params)
tire.search(load: true) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
sort { by :created_at, "desc" } if params[:query].blank?
end
end
def to_indexed_json
to_json(methods: [:user_first_name, :user_display_name])
end
def user_first_name
self.user.first_name if self.user.present?
end
def user_display_name
self.user.display_name if self.user.present?
end
end
Then, in my view, I have two loops:
- #posts.each do |post|
%h3
= post.name
- #channels.each do |channel|
%h3
= channel.title
Again – my goal is to execute one search, and display the results of posts and channels jumbled together using one loop.
Any help would be greatly appreciated... I'm pulling my hair out with this one!
UPDATE
Adding app trace...
app/controllers/posts_controller.rb:111:in `[]'
app/controllers/posts_controller.rb:111:in `block in browse'
app/controllers/posts_controller.rb:110:in `browse'
ANSWER
I replaced my browse action in the controller with:
def browse
#user = current_user
#search_items = Tire.search(['posts_index', 'channels_index'],{load: true}) do |search|
if params[:query].present?
search.query do |q|
q.string params[:query], default_operator: "AND"
end
end
search.sort { by :created_at, "desc" }
end
#results = #search_items.results
end
And then looped through #results in the view – and it worked!
You can use,
def browse
#search_items = Tire.search(['posts_index', 'channels_index'],{load: true}) do |search|
search.query do |q|
q.string params[:query], default_operator: "AND" if params[:query].present?
end
search.sort { by :created_at, "desc" } if params[:query].blank?
end
#results = #search_items.results
end

Elasticsearch / Tire - Flattening Nested Objects

In reference to the Query DSL Explained Tutorial Slides 14-15
How do I flatten Nested Objects?
I have a Model named Entry and another named Category and they share a HABTM association.
Everything is currently working and the search results seem to be correct, but I don't know if my mapping is correct. The tutorial says that when you flatten objects the Document will look like this :
{
tweet => "Perl is GREAT!",
posted => "2011-08-15",
user.name => "Clinton Gormley",
user.email => "drtech#cpan.org",
tags => ["perl","opinion"],
posts => 2,
}
with the Object user being flattened. When I look at the source of my JSON document it looks like this:
{
"title":"First",
"description":"first test",
"categories":
{"categories_name":"CAP and Using the CAP website"},
"attachment":"VEVTVCE=\n",
"published":true
}
So, I'm assuming that its supposed to say categories.categories_name but I don't know how to specify that or if that's even necessary. Here's some Model code:
class Entry < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
has_and_belongs_to_many :categories
mount_uploader :doc, EntryDocUploader
tire.mapping do
indexes :title
indexes :description
indexes :categories do
indexes :categories_name, type: 'string', index: 'not_analyzed'
end
indexes :attachment, :type => 'attachment',
:fields => {
:title => { :store => 'yes' },
:attachment => { :term_vector => 'with_positions_offsets', :store => 'yes' }
}
end
def to_indexed_json
{
:title => title,
:description => description,
:categories => {:categories_name => cats}, #categories.map { |c| { :categories_name => c.name}}.to_sentence,
:attachment => attachment,
}.to_json
end
def self.search(params)
tire.search(load: true) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
filter :term, :published => "true"
end
end
def cats
categories.map(&:name).to_sentence
end
end

Rails ElasticSearch Tire - filter nested field on multiple parameters the same time

I have a Movie model and a search page that has a movie genres facet.
It's possible to select a checkbox near every facet on the search page.
I pass the list of checked facet terms to a controller and I want to filter movies collection to include only those movies that have genres selected with checkboxes.
My model with indexes and search definition is:
class Movie < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :id, :index => :not_analyzed
indexes :title, :analyzer => 'snowball', :boost => 100
indexes :description, :analyzer => 'snowball'
indexes :genres do
indexes :title, analyzer: 'keyword'
end
end
def to_indexed_json
to_json( include: { genres: { only: [:title, :id] } } )
end
def self.search(params={})
tire.search(page: params[:page], per_page: 5, load: false) do
query do
all
#boolean do
# must { string params[:query], :default_field => 'title' }
#end
end
#filter 'genres.title', :values => params[:genres] if params[:genres].present?
filter :terms, 'genres.title' => ['Genre 1', 'Genre 2', 'Genre 3']
facet 'global-genres', global: true do
terms 'genres.title', size: 15
end
facet 'scoped-genres' do
terms 'genres.title', size: 15
end
end
end
attr_accessible :description, :title, :year, :genres
has_and_belongs_to_many :genres, :uniq => true
end
I'm not sure how this part should be rewritten:
#filter 'genres.title', :values => params[:genres] if params[:genres].present?
filter :terms, 'genres.title' => ['Genre 1', 'Genre 2', 'Genre 3']
#filter 'genres.id', :values => [1, 2, 3]
Later, I'm going to pass the list of genres or genre IDs as parameters, and I need to filter on them.
filter :terms, 'genres.title' => ['Genre 1', 'Genre 2', 'Genre 3']
It filters to movies that have 'Genre 1' OR 'Genre 2' OR 'Genre 3'
I need those genres to have AND logic.
How can I do this properly?
You need to set the filter with execution: 'and'. I've added this as an example to Tire integration test suite:
s = Tire.search('articles-test') do
query { all }
filter :terms, :tags => ['ruby', 'python'], :execution => 'and'
end

Tire not seeing singular/plural?

From everything I have read this should work. I'm re-indexing after each change.
My category names are stored as plural, e.g. "books", "movies" or "tapes". In rails terms this is the same as #resource.category.name
It works if i search books but does not work if i search book. I'm trying to make it so you can search either singular or plural and find a result for the category
# Tire
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :url
indexes :title, :boost => 3
indexes :description, :boost => 2
indexes :categories do
indexes :name, analyzer: 'snowball', :boost => 1.5, store: 'true'
end
indexes :user do
indexes :username, analyzer: 'keyword'
end
end
def self.elasticsearch(params)
tire.search(
:load => { :include => [:tags] },
:page => params[:page],
:per_page => 20) do
query { string params[:e], default_operator: "OR" } # if params[:e].present?
end
end
def to_indexed_json
to_json( include: { user: { only: [:username] },
category: { only: [:name] } } )
end

Resources