Tire/Mongoid Single Table Inheritance - Searching over mutliple models - ruby-on-rails

I'm trying to get STI working with tire/mongoid since hours. I hope someone can help me.
I've two models with different indexes. It should be possible to search both indexes over Event.search but also to search only the appropiate index with CoursePlan.search.
First Model: Event
# encoding: utf-8
class Event
include Mongoid::Document
include Mongoid::Timestamps
include Tire::Model::Search
include Tire::Model::Callbacks
# rest of class omitted...
# Elasticsearch
index_name "events" # Indexname /initializers/tire.rb
mapping do
indexes :_id, :index => :not_analyzed
indexes :title
indexes :place
indexes :description
indexes :fill_out
indexes :current_user_keyword, analyzer: "keyword"
end
Second Model: CoursePlan
# encoding: utf-8
class CoursePlan < Event
include Mongoid::Document
include Mongoid::Timestamps
include Tire::Model::Search
include Tire::Model::Callbacks
include TimeHelper
# rest of class omitted...
# Elasticsearch
index_name "course_plans"
tire.index.add_alias "events"
mapping do
indexes :_id, :index => :not_analyzed
indexes :title
indexes :place
indexes :description
indexes :fill_out
indexes :user_email
indexes :course_title
indexes :course_area
indexes :course_user_email
indexes :date
end
I've tried already the solution from richarddong, see tire issue #178. But this only seems to work under some circumstances.
Is there a working solution for this problem? Maybe i just got something wrong.
Thank you for your time.

Please check this answer,
Search multiple models with Tire and ElasticSearch
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

Related

Get all records without childrens even if they exists in elasticsearch

I am using elasticsearch_rails gem to do elasticsearch queries.
I have mappings like this
mapping do
indexes :id, type: 'keyword'
indexes :name, type: 'text'
indexes :slug, type: 'keyword'
indexes :variants, type: 'nested' do
indexes :id, type: 'keyword'
indexes :sku, type: 'keyword'
indexes :main, type: 'boolean'
indexes :price, type: 'float'
end
end
def as_indexed_json(options = {})
as_json(only: ['id', 'name', 'slug'],
include: {
variants: {
only: ['id', 'sku', 'main', 'price']
}
})
end
and what I am trying to do is to get all "parents" element, but without "variants". I mean I want to get all products without variants even if they have some variants.
I am trying to do it because when I have a product with large amount of variants (fe. product with 2.5k variants) elasticsearch returns me whole "collection" (product and all of its variants) and if I'm going to list 20 products with 2k variants each its gonna took forever.
I am retrieving all products with simple Product.elasticsearch.search('*') query
Regards.
To not transport all source data, the elasticsearch keyword to use is "_source" https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html

How can I do search category.name by using elasticsearch in Rails?

My search working fine.
But I have to type "1" or "2" to get results of "roommate" or "sublet".
Model has a column called category_id which is an integer.
Model Category has column :name which is a string.
Thus, I have category_id 1 is having "roommate" and 2 is "sublet"
below is my Housing model:
class Housing < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :category_id, :presence => true
validates :created_at, :presence => false
validates :user_email, :presence => true
validates :description, :presence => false
validates_length_of :title, :maximum => 30
def self.search(query)
__elasticsearch__.search(
{
query: {
# multi_match: {
simple_query_string: {
query: query,
fields: ['title^10', 'category_id']
}
}
}
)
end
end
How can I fix fields: ['title^10', 'category_id'] So user can search "roommate" instead of must search integer "1" to get result of roommate ?
I tried fields: ['title^10', 'category.name'] but not working.
fields: ['title^10', 'category.name'] won't work unless you have correct mapping defined. Elasticsearch doesn't know about your associations. ES is a document store and searches for records using it's own document store. So unless you add your category name to the document stored in ES, you won't be able to search it.
TL;DR
Define a mapping. Example:
mapping dynamic: 'strict' do
indexes :category do
indexes :name
end
indexes :title
end
Here category will now be stored as nested object inside your index and hence is searchable using category.name

Best way to search for human names with elasticsearch rails?

I have the following setup in my Rails 4 application via the elasticsearch-rails gem. If I search for a technical term such as "appellate" in the description field (which may be repeated more than once), I get back search results. But if I search for a name, whether first, last, or first and last, I seem to get nothing. Am I supposed to do something for string type fields? (keeping in mind that description is a text field in Rails and first and last names are string fields in Rails) Keep in mind that a first name such as "John" only appears in the first name field (last name is analogous to this), so I wonder if that is part of the issue?
class Trial < ActiveRecord::Base
include ActiveModel::Serialization
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
index_name [Rails.env, model_name.collection.gsub(/\//, '-')].join('_')
settings index: { number_of_shards: 2 } do
mappings dynamic: 'false' do
indexes :first_name, analyzer: 'english', index_options: 'offsets', copy_to: 'full_name'
indexes :last_name, analyzer: 'english', index_options: 'offsets', copy_to: 'full_name'
indexes :email, analyzer: 'english', index_options: 'offsets'
indexes :description, analyzer: 'english', index_options: 'offsets'
indexes :full_name, analyzer: 'english', index_options: 'offsets'
end
end
def self.search_trials(search_terms)
response = ClinicalTrial.search(
size: 20,
query: {
multi_match: {
"query" => search_terms,
"type" => "cross_fields",
"fields" => "_all"
}
}
)
response.records
end
end

How to perform ElasticSearch query on records from only a certain user (Rails Tire gem)

I have a Mongoid model which I perform ElasticSearch search queries on. Very standard:
class ActivityLog
include Mongoid::Document
include Mongoid::Timestamps
include Tire::Model::Search
include Tire::Model::Callbacks
field :extra, type: Hash
belongs_to :user, :inverse_of => :activity_logs
def self.search(params, user)
tire.search(load: true, page: params[:page], per_page: 5) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
sort { by :created_at, "desc" }
end
end
I am having a hard time understanding the documentation on how to do more advanced stuff, and currently I'm stuck in how to work into my search query that search should be restricted to ActivityLog objects that belongs to the user only.
Could anyone show me how to work the user._id match requirement into the search query?
Working with ElasticSearch, there are 2 parts: mapping and search
So, if you want to search by a field of association table (users table), right. There are many ways, but this one I often use for my project:
Inside the ActivityLog model
mapping do
indexes :id, type: 'integer'
indexes :name, type: 'string', analyzer: 'snowball', boost: 5
indexes :description, type: 'string', analyzer: 'snowball'
indexes :description_latin, as: 'description.sanitize', type: 'string', analyzer: 'snowball'
indexes :user_id, as: 'user.id', type: 'string', index: :not_analyzed
indexes :user_name, as: 'user.name', type: 'string'
indexes :created_at, type: 'date'
indexes :slug, index: :not_analyzed
indexes :publish, type: 'boolean', index: :not_analyzed
end
Notify the user_id and user_name, the above definition of mapping method will map the user.id to the user_id, and user.name to user_name.
So now in search method, you can do some similar code like
filter :terms, user_id: params[:search][:user_id]
Hope this help
One correction to the above, ElasticSearch has dropped the type string and now uses text.

Sorting by number of nested elements with ElasticSearch and Tire

Given the following mapping on a model called Post, is it possible to build a query that returns posts ordered by the number of votes cast within a specific time range (eg. past 7 days)?
mapping do
indexes :id, type: 'integer'
indexes :user_id, type: 'integer'
indexes :name, boost: 10
indexes :body # analyzer: 'snowball'
indexes :created_at, type: 'date'
indexes :vote_count, type: 'integer'
indexes :topic_ids
indexes :topics do
indexes :id, type: 'integer'
indexes :name, type: 'string'
end
indexes :votes do
indexes :user_id, type: 'integer'
indexes :created_at, type: 'date'
end
end
I'm using Tire in Rails 3.2.13. I have a Post model and a Vote model. A Post has many votes, and a Vote belongs to Post.
Yes, you can either sort on the vote_count atrribute, or use the custom_score query for fine-grained relevancy computation.
For the former, something like:
require 'tire'
s = Tire.search do
query do
filtered do
query { all }
filter :range, 'created_at' => { from: '-7d' }
end
end
sort do
by :vote_count
end
end
puts s.to_curl

Resources