How to use Tire for "MoreLikeThis" query of ElasticSearch - ruby

I would like execute this exemple :
$ curl -XGET 'http://localhost:9200/twitter/tweet/1/_mlt?mlt_fields=tag,content&min_doc_freq=1'
with Tire gem. It's poossible ?
My goal to search document related to another document.

It is not implemented directly in tire. Karmi, however, has implemented it as a tire extension in the tire-contrib repository.
Source Code: more_like_this.rb
Add by adding gem 'tire-contrib'
more_like_this_field(:tag, like_text, options = {min_doc_freq: 1})

Okay the internet forgot to include a single example of this call (including the source project), so here is one style of it.
related_articles = Article.search {
query {
more_like_this("#{current_article.title} #{current_article.body}",
fields: [:title, :description],
percent_terms_to_match: 0.1,
min_term_freq: 1,
min_doc_freq: 1
)
}
}
puts related_articles.results.count
puts related_articles.results.first.title if related_articles.present?
The gotcha here are the min_term_freq and min_doc_freq params above. They default to 2 and 5 respectively in ElasticSearch, which makes it easy to get confused while testing this.

Related

Google custom search json api refinement labels

I am building out a site search using the google custom json/rest api, but I am not sure how to get the 'facet/ refinement labels' to filter down the results.
They are being returned in the json, but I haven't seen anything in the documentation that explains how to filter with it.
To filter with facet, value of q parameter should be like this:
text_to_search more:facet_name
After you have added refinement labels to your custom search, you have to add the facet name into your search query to "activate" the filter. Your facet name will be named the same as you named your refinement label. If you named your refinement label "race bicycles", you need to add more:race_bicycles to your query. You can also find your facet name in the response meta data of your request in label_with_op. Just copy and past your label_with_op in your query.
For using the api in python, the request looks something like this:
params = {
"q" : "bicycles more:race_bicycles",
"cx": cx,
"key": key,
}
page = requests.request("GET", url = "https://www.googleapis.com/customsearch/v1" , params=params)
results = json.loads(page.text)

Rails 4 and Mongoid: programmatically build query to search for different conditions on the same field

I'm building a advanced search functionality and, thanks to the help of some ruby fellows on SO, I've been already able to combine AND and OR conditions programmatically on different fields of the same class.
I ended up writing something similar to the accepted answer mentioned above, which I report here:
query = criteria.each_with_object({}) do |(field, values), query|
field = field.in if(values.is_a?(Array))
query[field] = values
end
MyClass.where(query)
Now, what might happen is that someone wants to search on a certain field with multiple criteria, something like:
"all the users where names contains 'abc' but not contains 'def'"
How would you write the query above?
Please note that I already have the regexes to do what I want to (see below), my question is mainly on how to combine them together.
#contains
Regex.new('.*' + val + '.*')
#not contains
Regex.new('^((?!'+ val +').)*$')
Thanks for your time!
* UPDATE *
I was playing with the console and this is working:
MyClass.where(name: /.*abc.*/).and(name: /^((?!def).)*$/)
My question remains: how do I do that programmatically? I shouldn't end up with more than two conditions on the same field but it's something I can't be sure of.
You could use an :$and operator to combine the individual queries:
MyClass.where(:$and => [
{ name: /.*abc.*/ },
{ name: /^((?!def).)*$/ }
])
That would change the overall query builder to something like this:
components = criteria.map do |field, value|
field = field.in if(value.is_a?(Array))
{ field => value }
end
query = components.length > 1 ? { :$and => components } : components.first
You build a list of the individual components and then, at the end, either combine them with :$and or, if there aren't enough components for :$and, just unwrap the single component and call that your query.

Tire filtering not working?

So, I have a class called Fundraiser:
class Fundraiser
def search!
search = Tire::Search::Search.new('fundraisers')
search.query { all }
search.filter :range, {id: {gt: 1}}
search.results
binding.pry
end
end
When I pry into it and view the "search" variable I get no results
[1] pry()> search
=> #<Tire::Search::Search:0x007fb3d9d13938
#filters=[{:range=>{:id=>{:gt=>1}}}],
#indices=["fundraisers"],
#options={},
#path="/fundraisers/_search",
#types=[]>
Even though I have two Fundraisers with IDs higher than "1"
[2] pry()> Fundraiser.all.map(&:id)
=> [1, 2, 3]
What am I doing wrong? I've rewritten this every way I can think of. Also of note, if I do a similar filter on say, "created_at" being gt/lt a timestamp I get no results.
Update:
I've added the query and results part of the search call and I'm not getting results still...
=> #<Tire::Results::Collection:0x007f92f3302b58
#facets=nil,
#max_score=0.0,
#options={},
#response=
{"took"=>0,
"timed_out"=>false,
"_shards"=>{"total"=>5, "successful"=>5, "failed"=>0},
"hits"=>{"total"=>0, "max_score"=>nil, "hits"=>[]}},
#time=0,
#total=0,
#wrapper=Tire::Results::Item>
You've created a search but you haven't executed it (by calling .results on it)
Furthermore I'm pretty sure you'll have to define a query, even if it is just
search.query { all }
You may also wish to considered using a filtered query, although adding filters at the top level will work too.

Mongodb simple update does not work in Ruby/Mongoid

I have the following MongoDB update operation, but it doesnt seem to work, anyone know why?
User.collection.update({ _id: BSON::ObjectId("5018ed448712ff240e0000a0") },
{ "$set" => { name: "ben" } })
It does not throw an error, but just some integer which I am guessing is the doc size.
I am using Mongoid 2.4.10/Rails 3.2.7
If you are using Mongoid, you coule just do a find and update:
User.find("5018ed448712ff240e0000a0").update_attributes!(name: "ben")
or you could use set:
User.find("5018ed448712ff240e0000a0").set(:name, "ben")
Note that set() takes 2 arguments; it does not accept a hash as an argument
Can you use mongoid API instead and use following command:
User.find("5018ed448712ff240e0000a0").set(name: "ben")

Mongodb and Ruby gem - Check if record exists

I've a simple Ruby script (no rails, sinatra etc.) that uses the Mongo gem to insert records into my DB as part of a Redis/Resque worker.
Upon occasion instead of doing a fresh insert I'd like to update a counter field on an existing record. I can do this handily enough with rails/mysql. What's the quickest way of doing this in pure Ruby with Mongodb?
Thanks,
Ed
The Ruby client library for MongoDB is very convenient and easy to use. So, to update a document in MongoDB, use something similar to this:
#!/usr/bin/ruby
require 'mongo'
database = Mongo::Connection.new.db("yourdatabasename")
# get the document
x = database.find({"_id" => "12312132"})
# change the document
x["count"] = (x["count"] || 0) + 1
# update it in mongodb
database["collection"].update("_id" => "thecollectionid", x)
You might want to check out the manual for updating documents in MongoDB as well.
thanks to envu's direction I went with upsert in the end. here is an example snippet of how to use it the Ruby client:
link_id = #globallinks.update(
{
":url" => "http://somevalue.com"
},
{
'$inc' => {":totalcount" => 1},
'$set' => {":timelastseen" => Time.now}
},
{
:upsert=>true
}
)

Resources