Thinking Sphinx - Globalize - ruby-on-rails

I've set up Thinking Sphinx gem https://github.com/pat/thinking-sphinx
and I'm trying to get it work with globalize https://github.com/globalize/globalize gem.
I have a model named Content that has :name, :body ,:summary attributes and also has
translates :name, :body, :summary, :fallbacks_for_empty_translations => true
for translations.
I've created a content_index that has
ThinkingSphinx::Index.define :content, :with => :active_record do
indexes translations.summary, :sortable => true
indexes translations.body , :sortable => true
where "content_translations.locale = 'my_locale'"
end
When I do rake ts:index or rake ts:rebuild I get
Generating configuration to
rails_app_path/config/development.sphinx.conf Sphinx
2.1.8-id64-release (rel21-r4675) Copyright (c) 2001-2014, Andrew Aksyonoff Copyright (c) 2008-2014, Sphinx Technologies Inc
(http://sphinxsearch.com)
using config file 'rails_app_path/config/development.sphinx.conf'...
indexing index 'content_core'...
collected 43 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 43 docs, 3266 bytes
total 0.005 sec, 616808 bytes/sec, 8120.86 docs/sec
skipping non-plain index 'content'...
total 3 reads, 0.000 sec, 1.3 kb/call avg, 0.0 msec/call avg
total 10 writes, 0.000 sec, 1.5 kb/call avg, 0.0 msec/call avg
rotating indices: successfully sent SIGHUP to searchd (pid=8282).
So when I get to rails console (rails c) and try something like
Content.search "something"
I get empty results.
2.1.2 :050 > Content.search("something")
Sphinx Query (0.6ms) SELECT * FROM content_core WHERE
MATCH('something') AND sphinx_deleted = 0 LIMIT 0, 20
Sphinx Found 0 results
=> []
Does skipping non-plain index 'content'... line in ts:rebuild task has anything to do with it?

Related

Formula for calculating user experience

I would like (without using a gem) to create a level and experience point system for my users.
When creating his account, he starts level 0 with 0 experience points. To reach level 1 he will need 10 additional points, for a total of 10 points. For level 3 he will need 30 additional points, for a total of 60 experience points. Each additional level requires 10 more experience points. (see example below).
Level | Total XP | XP for next level|
----------------------------------------|
0 | 0 | 10 |
1 | 10 | 20 |
2 | 30 | 30 |
3 | 60 | 40 |
4 | 100 | 50 |
5 | 150 | 60 |
etc...
I would like an xp column in my user table that would represent the total experience of a user.
In my view I would like to display its level. But what is the formula for calculating this?
Let's imagine that my user has 157 experience points in total. Which corresponds to a level 5. How to calculate a level only via the total experience points and how to calculate this regardless of its total experience point whether it is 38 like 369 or 4393.
I'm not sure if this is exactly what you wanted. It's more of an algorithm than a formula, but here is a method that will return the proper level based on the experience given. Think of the bar variable like the bar you have to get over to meet a new level, and think of the step variable like the amount of experience added between each level (as you describe in your right-most column).
def calculate_level(experience)
level = 0
bar = 10
step = 10
while experience >= bar
level += 1
step += 10
bar += step
end
level
end
Example output:
irb> calculate_level(0) # => 0
irb> calculate_level(9) # => 0
irb> calculate_level(10) # => 1
irb> calculate_level(11) # => 1
irb> calculate_level(29) # => 1
irb> calculate_level(30) # => 2
irb> calculate_level(31) # => 2
irb> calculate_level(59) # => 2
irb> calculate_level(60) # => 3
irb> calculate_level(61) # => 3
irb> calculate_level(99) # => 3
irb> calculate_level(100) # => 4
irb> calculate_level(101) # => 4
irb> calculate_level(149) # => 4
irb> calculate_level(150) # => 5
irb> calculate_level(151) # => 5
Calculate the inverse of my above comment and take the floor:
def calculate_level experience
(Math.sqrt(0.2 * experience + 0.25) - 0.5).floor
end
You can use such "formula"
def calculate_level(experience)
(1..).find { |i| (experience -= 10 * i).negative? } - 1
end
Just decrease experience on 10x steps every time and check if result is not negative
calculate_level(0)
# => 0
calculate_level(9)
# => 0
calculate_level(10)
# => 1
calculate_level(11)
# => 1
calculate_level(29)
# => 1
calculate_level(30)
# => 2
calculate_level(31)
# => 2
calculate_level(59)
# => 2
calculate_level(60)
# => 3
calculate_level(61)
# => 3
calculate_level(99)
# => 3
calculate_level(100)
# => 4
calculate_level(101)
# => 4
calculate_level(149)
# => 4
calculate_level(150)
# => 5
calculate_level(151)
# => 5
calculate_level(209)
# => 5
calculate_level(210)
# => 6

Acts_as_taggable_on index too long

I am trying to use the acts_as_taggable_gem but I am having issues with the migration.
in the automatically generated ActsAsTaggableOnMigration file I am getting the following error
Mysql2::Error: Specified key was too long; max key length is 767
bytes: CREATE INDEX
'index_taggings_on_taggable_id_and_taggable_type_and_context' ON
'taggings' ('taggable_id', 'taggable_type', 'context')
on the line add_index :taggings, [:taggable_id, :taggable_type, :context]
I have used the gem on another project successfully in the past. The only difference is this time the database charset is utf8mb4, This is a requirement to support emojis.
I have tried reducing the :limit (default is 128) on the :context to no avail
You can solve this issue in two ways:
Changing your storage engine (MySQL) from InnoDB to MyISAM, MyISAM supports 1000 bytes long prefix for indexing, whereas InnoDB support 767 bytes.
Or by specifying context length:
add_index :taggings, [:taggable_id, :taggable_type, :context], name: 'by_id_type_context', length: {context: 128}
# => CREATE INDEX by_id_type_context ON taggings(taggable_id, taggable_type, context(128))
Note: SQLite doesn’t support index length.

Thinking sphinx geosearch issues

I need to search locations with sort by distance from passed coordinates.
app/indices/location_index.rb
ThinkingSphinx::Index.define :location, :with => :active_record do
indexes :name
has latitude, longitude
end
Try to search:
> Location.search(:geo => [53.348962, 83.777988], :order => "#geodist DESC").size
ThinkingSphinx::SyntaxError: sphinxql: syntax error, unexpected USERVAR, expecting IDENT (or 5 other tokens) near '#geodist DESC LIMIT 0, 20; SHOW META'
> Location.search(:geo => [53.348962, 83.777988],:with => {"#geodist" => 0.0..5000.0}, :order => "#geodist DESC").size
ThinkingSphinx::SphinxError: sphinxql: only >=, <=, and BETWEEN floating-point filter types are supported in this version near '#geodist BETWEEN 0.0 AND 5000.0 AND sphinx_deleted = 0 ORDER BY #geodist DESC LIMIT 0, 20; SHOW META'
Sphinx 2.0.6-release (r3473; Oct 22, 2012)
thinking-sphinx (3.0.1)
Update:
Pat Allan suggested:
Geodist no longer requires the # symbol - so try the following instead:
Location.search(:geo => [53.348962, 83.777988], :order => "geodist DESC").size
Location.search(:geo => [53.348962, 83.777988],:with => {:geodist => 0.0..5000.0}, :order => "geodist DESC").size
Just in case people find this question thought I'd add the answer in the correct format and with a little more explanation.
Versions of Sphinx prior to 2.1.1 made the calculated distance available via the #geodist internal variable. In versions of Thinking Sphinx compatible with newer versions of Sphinx the value of GEODIST() has been aliased to geodist.
So this:
Location.search(:geo => [53.348962, 83.777988], :order => "#geodist DESC").size
Becomes:
Location.search(:geo => [53.348962, 83.777988], :order => "geodist DESC").size
It's also worth pointing out in this example that the coordinates being supplied in the above example are in the incorrect format. They're in degrees rather than radians: http://pat.github.io/thinking-sphinx/geosearching.html. To transform them you can do:
def degrees_to_radians(degrees)
degrees * Math::PI / 180
end
Hope that helps!

Thinking Sphinx and Norwegian characters (æ, ø, å)

I've set up Thinking Sphinx for wildcard searches, but I'm having trouble searching for words containing Norwegian characters, as the automatic starring seems to mess up the query. For instance, my search for "ål" will end up with:
Sphinx Query (2.8ms) å*l*
Sphinx Found 0 results
If I manually enter the stars in the search term, "*ål*", the expected results are returned:
Sphinx Query (3.7ms) *ål*
Sphinx Found 8 results
It seems somehow the å (as well as æ, ø) gets misinterpreted when automatically adding the stars.
Anyone here familiar with this problem?
My config/sphinx.yml looks as follows:
development:
enable_star: 1
min_infix_len: 2
charset_table: "U+FF10..U+FF19->0..9, U+FF21..U+FF3A->a..z, U+FF41..U+FF5A->a..z, 0..9, A..Z->a..z, a..z,
U+C5->U+E5, U+E5, U+D8->U+F8, U+F8, U+C6->U+E6, U+E6,
U+C4->U+E4, U+E4, U+D6->U+F6, U+F6"
And a couple of examples of searches performed in the console:
ruby-1.9.2-p290 :014 > ThinkingSphinx.search("ål", :star => true).count
=> 0
ruby-1.9.2-p290 :015 > ThinkingSphinx.search("*ål*", :star => true).count
=> 8
This has been fixed in recent commits - for the moment, you'll need to grab it via the repo:
gem 'thinking-sphinx',
:git => 'git://github.com/freelancing-god/thinking-sphinx.git'

Friendly Byte Formatting in Rails

I need to format an integer representation of bytes into something friendly, and I'm hoping that there's a utility function in Ruby or in Rails that will do that formatting for me (to perpetuate my laziness, of course.)
I'm looking for something that would look like:
format_bytes(1024) -> "1 KB"
format_bytes(1048576) -> "1 MB"
Looks like there's some stuff in ActiveSupport to do it the other way around, but I haven't found a way to do it in this direction.
If there isn't one that exists, does anyone have a particularly elegant solution?
Number to human size is what you're looking for.
require 'action_view'
include ActionView::Helpers::NumberHelper
number_to_human_size(123) # => 123 Bytes
number_to_human_size(1234) # => 1.2 KB
number_to_human_size(12345) # => 12.1 KB
number_to_human_size(1234567) # => 1.2 MB
number_to_human_size(1234567890) # => 1.1 GB
number_to_human_size(1234567890123) # => 1.1 TB
number_to_human_size(1234567, :precision => 2) # => 1.18 MB
number_to_human_size(483989, :precision => 0) # => 473 KB
number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
Accepted answer still work, but requires actionpack instead of actionview in newer rails.
require 'actionpack'
Accepted answer it's perfect, but I didn't need the first two lines.
I only put:
number_to_human_size(123) # => 123 Bytes
number_to_human_size(1234) # => 1.2 KB
number_to_human_size(12345) # => 12.1 KB
number_to_human_size(1234567) # => 1.2 MB
number_to_human_size(1234567890) # => 1.1 GB
number_to_human_size(1234567890123) # => 1.1 TB
number_to_human_size(1234567, :precision => 2) # => 1.18 MB
number_to_human_size(483989, :precision => 0) # => 473 KB
number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
and works like a charm.

Resources