Rails ElasticSearch model with fields - ruby-on-rails

I'm using elasticsearch-rails and mongoid
I have the following simple mapping with fields:
"title": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
My model looks like this:
class ArticlesEvent
include Mongoid::Document
include Elasticsearch::Model
field :title, type: String
attr_accessible :title
def as_indexed_json(options={})
as_json(except: [:id, :_id])
end
Can anyone show an example how to define the rails model with the title.raw field, and how to access that field? Since the multi fields have been deprecated it's hard to find a working example with rails and mongoid.
Thanks

You should be able to achieve this with the following attribute definition in your model:
attribute :title, String, mapping: {
fields: {
raw: { type: 'string', index: 'not_analyzed' }
}
}

Looks like this is still an open issue with elasticsearch-rails: https://github.com/elastic/elasticsearch-rails/issues/79

You can define below mapping in your model
indexes :name_of_field,type: :keyword, fields: {
raw: {
type: :text
}
}

Related

How to implement a method in ruby to load images from the backend app

I want to implement method in ruby to load images from the backend app but I don't know how. I have been trying with image_tag directly from a view to call the location /image/{imageId} or /image/{documentId} but no success obviously. This is what I get from the backend api:
[
{
"imageId": "1",
"srcDocumentId": 10000,
"scopes": null,
"teiId": "",
"name": "image",
"headline": "Fig. 1. ",
"description": "Fig. 1. GPA",
"inBody": true,
"image": "a long string",
"internalUrl": "image.png",
"source": "<figure xmlns=\"http://www.tei-c.org/ns/1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xml:id=\"fig_3\"><head>Fig. 1. </head><figDesc>Fig. 1. GPA</figDesc><graphic coords=\"4,130.95,64.62,360.00,502.42\" type=\"bitmap\" url=\"image.png\"/></figure>",
"ord": 0
}
]
Any help would be appreciated. Even if you tell me only the logic on how should I handle this in a model and then at the view.
Edit:
Let's say I want to show the headline and description of the image first. I have this in document_helper.rb :
def images_format(image)
m = []
m << [['Description:', image.description]] if image.description
m << [
['Headline', image.headline]
] if image.headline.any?
m
end
in document.rb I have this:
class Image
include Mongoid::Document
field :description, type: String
field :headline, type: String
field :image, type: String
field :imageId, type: String
field :image, type: String
field :srcDocumentId, type: Integer
field :internalUrl, type: String
field :name , type: String
field :internalUrl, type: String
field :source, type: String
end
and also this:
embeds_one :image, class_name: 'Document::Image'
embeds_one :image, class_name: 'Document::Image'
and in the view document_show.haml I put:
.document__body= images_format(#document.image)
I get this error: undefined method 'description' for nil:NilClass

Spell check Ngram for elastic Search not working with rails

I have used in my model to include spell check such that if the user inputs data like "Rentaal" then it should fetch the correct data as "Rental"
document.rb code
require 'elasticsearch/model'
class Document < ApplicationRecord
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
belongs_to :user
Document.import force: true
def self.search(query)
__elasticsearch__.search({
query: {
multi_match: {
query: query,
fields: ['name^10', 'service']
}
}
})
end
settings index: {
"number_of_shards": 1,
analysis: {
analyzer: {
edge_ngram_analyzer: { type: "custom", tokenizer: "standard", filter:
["lowercase", "edge_ngram_filter", "stop", "kstem" ] },
}
},
filter: {
edge_ngram_filter: { type: "edgeNGram", min_gram: "3", max_gram:
"20" }
}
} do
mapping do
indexes :name, type: "string", analyzer: "edge_ngram_analyzer"
indexes :service, type: "string", analyzer: "edge_ngram_analyzer"
end
end
end
search controller code:
def search
if params[:query].nil?
#documents = []
else
#documents = Document.search params[:query]
end
end
However, if I enter Rentaal or any misspelled word, it does not display anything.
In my console
#documents.results.to_a
gives an empty array.
What am I doing wrong here? Let me know if more data is required.
Try to add fuzziness in your multi_match query:
{
"query": {
"multi_match": {
"query": "Rentaal",
"fields": ["name^10", "service"],
"fuzziness": "AUTO"
}
}
}
Explanation
Kstem filter is used for reducing words to their root forms and it does not work as you expected here - it would handle corectly phrases like Renta or Rent, but not the misspelling you provided.
You can check how stemming works with following query:
curl -X POST \
'http://localhost:9200/my_index/_analyze?pretty=true' \
-d '{
"analyzer" : "edge_ngram_analyzer",
"text" : ["rentaal"]
}'
As a result I see:
{
"tokens": [
{
"token": "ren"
},
{
"token": "rent"
},
{
"token": "renta"
},
{
"token": "rentaa"
},
{
"token": "rentaal"
}
]
}
So typical misspelling will be handled much better with applying fuzziness.

Rails Elasticsearch analyzer mappings defined in model are not reported in elasticsearch

In my Recipe model I have :
class Recipe < ActiveRecord::Base
index_name "recipes-#{Rails.env}"
settings do
mappings dynamic: 'false' do
indexes :title, type: 'string', analyzer: 'french'
indexes :description, type: 'string', analyzer: 'french'
end
end
def as_indexed_json(options={})
self.as_json({only: [:title, :description]})
end
Then in rails console, I launch Recipe.import. When asking to elasticsearch via curl or Sense GET /recipes-development/_mapping/, I get
{
"recipes-development": {
"mappings": {
"recipe": {
"properties": {
"description": {
"type": "string"
},
"title": {
"type": "string"
}
}
}
}
}
}
I have lost all informations about analyzer. Any idea would be appreciated
Before Recipe.import you have to execute
Recipe.__elasticsearch__.create_index! force: true

Sorting search results with mongoid-elasticsearch gem

I am trying to implement sorting into my search. I am searching with use of the gem mongoid-elasticsearch. This is my model configuration:
class ActivityLog
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Elasticsearch
elasticsearch!(
{
wrapper: :load,
sort: [
{ created_at: "desc" }
]
}
)
field :type, type: String
end
This configuration does not raise any errors, but it does not either seem like it has any effect, because search results are listed randomly.
I think I am implementing the configuration in accordance to the documentation:
Check mongoid-elasticsearch documentation here
Check elasticsearch documentation here
My search query btw is:
ActivityLog.es.search(params[:query], page: params[:page]).results.paginate(per_page: 5, page: params[:page])
You should remove Array wrapper:
elasticsearch!(
{
wrapper: :load,
sort: { created_at: "desc" }
}
)
The same way you would do it in Elasticsearch itself
ActivityLog.es.search({
body: {
query: {
query_string: {
query: params[:search]
}
},
sort: [
{created_at: {order: "asc"}},
]
})

ElasticSearch + Tire searching only on id field

I've looked everywhere but nothing can help me. And I can't figure out what is the problem.
my model
class Article
include Mongoid::Document
include Mongoid::Timestamps
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :_id, :index => :not_analyzed
indexes :title
indexes :body
end
def to_indexed_json
self.to_json
end
http://localhost:9200/articles/_mapping
{
"articles": {
"article": {
"properties": {
"$oid": {
"type": "string"
},
"body": {
"type": "string"
},
"title": {
"type": "string"
}
}
}
}
}
Article.search 'love' gives no results,but there are Article with title "love", I've tried to build many requests but nothing works.
all times the same results:
"hits"=>{"total"=>0, "max_score"=>nil, "hits"=>[]}}
But If I type: Article.search "cbc267c955464f22d72a0100" it gives me article with title: "love"
So it seems to me that tire create indexes only on ID field, regardless mapping indexes on model.
When I recreate indexes
Article.index_name
=> "articles"
Tire.index('articles').delete
=> true
Article.import
my mapping becomes:
{
"articles": {
"article": {
"properties": {
"$oid": {
"type": "string"
}
}
}
}
}
UPDATED
module BSON
class ObjectId
def as_json(*args)
to_s()
end
def to_json(*args)
MultiJson.encode(as_json())
end
end
end
After implementing this initialize, all seems to work fine
I too encountered such problems while using tire. After deleting the index, you can try Article.create_elasticsearch_index and Article.tire.index.import Article.all.
The _source field in your indexed document should have title,id and body included in it, which should make it available for search.
Anyways, tire is getting retired as elasticsearch gem has now been released.

Resources