ankane / Neighbor
Programming Languages
Labels
Projects that are alternatives of or similar to Neighbor
Neighbor
Nearest neighbor search for Rails and Postgres
Installation
Add this line to your application’s Gemfile:
gem 'neighbor'
And run:
bundle install
rails generate neighbor:install
rails db:migrate
This enables the cube extension in Postgres
Getting Started
Create a migration
class AddNeighborVectorToItems < ActiveRecord::Migration[6.1]
def change
add_column :items, :neighbor_vector, :cube
end
end
Add to your model
class Item < ApplicationRecord
has_neighbors dimensions: 3
end
Update the vectors
item.update(neighbor_vector: [1.0, 1.2, 0.5])
With cosine distance (the default), vectors are normalized before being stored
Get the nearest neighbors to a record
item.nearest_neighbors.first(5)
Get the nearest neighbors to a vector
Item.nearest_neighbors([0.9, 1.3, 1.1]).first(5)
Distance
Specify the distance metric
class Item < ApplicationRecord
has_neighbors dimensions: 3, distance: "euclidean"
end
Supported values are:
-
cosine
(default) euclidean
taxicab
chebyshev
For inner product, see this example
Records returned from nearest_neighbors
will have a neighbor_distance
attribute
nearest_item = item.nearest_neighbors.first
nearest_item.neighbor_distance
Dimensions
By default, Postgres limits the cube
data type to 100 dimensions. See the Postgres docs for how to increase this.
Example
You can use Neighbor for online item-based recommendations with Disco. We’ll use MovieLens data for this example.
Generate a model
rails generate model Movie name:string neighbor_vector:cube
rails db:migrate
And add has_neighbors
class Movie < ApplicationRecord
has_neighbors dimensions: 20
end
Fit the recommender
data = Disco.load_movielens
recommender = Disco::Recommender.new(factors: 20)
recommender.fit(data)
Use item factors for the neighbor vector
recommender.item_ids.each do |item_id|
Movie.create!(name: item_id, neighbor_vector: recommender.item_factors(item_id))
end
And get similar movies
movie = Movie.find_by(name: "Star Wars (1977)")
movie.nearest_neighbors.first(5).map(&:name)
History
View the changelog
Contributing
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/ankane/neighbor.git
cd neighbor
bundle install
bundle exec rake test