SlideShare uma empresa Scribd logo
1 de 59
Baixar para ler offline
How
 Richard
  Found
 Friends
Richard Schneeman
       @schneems




 I hack rubies for @gowalla
Meet Richard
•Richard needs more friends
 •Richard has one or more friends on
   our network

  •We can help him find more!
def
potential_friend
•Someone who Richard likely
 knows and wants to
 “friend” on a service (e.g.
 Gowalla)
def mutual_friend
•When two users have the same
 friend, it is a mutual friend
Richard’s Friends
Richard’s Friends
   John
Richard’s Friends
   John     Jane
Richard’s Friends
     John         Jane



 John’s Friends
Richard’s Friends
     John             Jane



 John’s Friends   Jane’s Friends
Richard’s Friends
     John             Jane



 John’s Friends   Jane’s Friends
Richard’s Friends
     John                    Jane



 John’s Friends        Jane’s Friends
                  }
            Mutual Friends
Friends of Friends
•Friends of friends are all potential
  friends

 •People are more likely to
   “friend” another user if they are
   a “friend of a friend”

•Mutual friend numbers provide a
  ranking system
Friends of Friends
John Doe’s   Jane Doe’s
  Friends      Friends
Friends of Friends
 John Doe’s   Jane Doe’s
   Friends      Friends
Friends of Friends
 John Doe’s   Jane Doe’s
   Friends      Friends




     +1          +1
Friends of Friends
 John Doe’s   Jane Doe’s
   Friends      Friends




     +1
          +2     +1
Friends of Friends
John Doe’s              Jane Doe’s
  Friends                 Friends




                 Justin Beiber’s
                     Friends
Friends of Friends
John Doe’s                         Jane Doe’s
  Friends                            Friends
                  +2
             +1        +1
             +2+3+2
                  +1
                            Justin Beiber’s
                                Friends
How do we do that
   in our App?
•Memcache
•Redis
•Street Smarts



                 (Making it rain friendships)
Memcache
•Key value store (NOSQL)
•Holds ruby objects> CACHE.set("foo",
                   "bar")=> nil

•Extremely fast
                   > CACHE.get("foo")
                   => "bar"


•volatile
•Used to (mem)cache database
 queries
Memcache
                                Key Value Store
> CACHE.set("foo", "bar")
> CACHE.get("foo")
=> "bar"


> user = User.where(:username => “Schneems”).first
> CACHE.set("foo", user)
> CACHE.get("foo")
=> #<User id: 263595 ... >

                        Marshals Ruby Objects
                                           (like a boss)
Memcache

 Is Volitile
Memcache Pattern
                                                       get||Set
 class Memcached

  def get_or(key, timeout=0, marshal=true, &block)
    get(key, marshal)
    rescue Memcached::NotFound => e
      if block_given?
        value = block.call
        set(key, value, timeout, marshal) rescue nil
        value
      else
        raise e
      end
  end

 end

                              gets the value || makes the
                               query and sets the cache
Memcache - Speed
     Tips
•Cache frequently queried objects
 (get users)
  class User < ActiveRecord::Base
    def self.get(username)
      CACHE.get_or("user:#{username}") do
        User.where(:username => "#{username}").first
      end
    end
  end

  >> User.get("schneems")
  => #<User id: 263595 ... >
Memcache:
(I wanna Go Fast)

   # Database
   > Benchmark.measure do
       User.where(:username => "schneems").first
     end.real
   => 0.09 s

   # Memcache
   > Benchmark.measure do
       User.get("schneems")
     end.real
   => 0.0009 s

                     oh yeah
Memcache - Speed
     Tips
•Cache expensive queries (Friend
   IDs)
class User < ActiveRecord::Base
  def get_friend_ids
    CACHE.get_or("friend_ids:#{self.id}") do
      friends = Friendships.where(:user_1_id => self.id)
      friends.map {|friend| friend.user_2_id }
    end
  end
end

>> u = User.get("schneems")
>> u.get_friend_ids
=> [1,2,3,...]
Memcache
• Key/Value store (NOSQL)
• Holds ruby objects
• Extremely fast
• volatile
• Can be used to cache expensive database
  queries    > CACHE.set("foo",
             "bar")=> nil
             > CACHE.get("foo")
             => "bar"
Redis
•Key value store (NOSQL: yes
 another one)

 •does NOT store ruby
   objects...boo :’ (

  •Native data structures...yay   :)

 •pretty-darn fast
 •non-volatile!!!!!!!!!!
Redis
                                         keys & values & stores
    > REDIS.set("chunky", "bacon")
    => "OK"
    > REDIS.get("chunky")
    => "bacon"




http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
Redis - Datatypes
• String
• Set
      (collection of strings with no duplicates)

• Sorted Set
• List
      (sorted collection of strings like and
      array)

http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
Redis - Lists
                                        keys & values & stores
> REDIS.lpush("lists:are:like:an:array", 1)
=> 1
> REDIS.lpush("lists:are:like:an:array", 2)
=> 2
> REDIS.lpush("lists:are:like:an:array", 3)
=> 3
> REDIS.lrange("lists:are:like:an:array", 0, -1)
=> ["3", "2", "1"]
> REDIS.lrange("lists:are:like:an:array", 0, -1).map(&:to_i)
=> [3, 2, 1]




http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
Redis - Lists
                              Store “ignored” potential friends
def ignore_potential_friend(friend_id)
    REDIS.lpush(ignore_facebook_friend_key, friend_id)
end



                                   Retrieve array of ignored IDs
def ignored_potential_friend_ids
    REDIS.lrange(not_potential_friend_ids_key, 0, -1).map(&:to_i)
end
Redis - Recap
•Key value store (yes another one)
 •does NOT store ruby
   objects...boo :’ (

  •Native data structures...yay   :)

 •pretty-darn fast
 •non-volatile!!!!!!!!!!
Redis - Extra
Getting Started
                Credit
    http://jimneath.org/2011/03/24/using-redis-with-ruby-
    on-rails.html

Resque
Background jobs with Redis (and style)
https://github.com/defunkt/resque
Street Smarts
  •Ruby array ‘tricks’
  •Connecting the dots

Memcache        Redis & Ruby



                           Potential Friends
Street Smarts
            Ruby array Manipulation
Intersection (    &)
 > [1,2,3] & [3,4,5]

 => [3]

 > [1,2,3,4] & [3,4,5]

 => [3,4]

Difference (    -)
 > [1,2,3] - [3,4,5]
 => [1,2,4,5]
 > [1,2,3,4] - [3,4,5]
 => [1,2,5]
Street Smarts
          Ruby array Manipulation
Concatenation (      +)
 > [1,2] + [3,4,5]
 => [1,2,3,4,5]
Street Smarts
            Ruby array Manipulation
inject - turning arrays into other
stuff
  [5,6,7,8,9,10].inject(0)   {|sum, n| sum + n }
  => 45
Street Smarts
            Ruby array Manipulation
inject - turning arrays into other
stuff
  [5,6,7,8,9,10].inject(0)   {|sum, n| sum + n }
  => 45



inject - build hashes from arrays
  > array = [5,6,7,8,9,10]
  > array.inject({}) {|hash, id| hash[id.to_s] = 1; hash }
  => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
inject - build hashes from arrays
       > array.inject({}) {|hash, id|
                            puts "hash: #{hash.inspect}"
                            puts "id: #{id}"
                            hash[id.to_s] = 1;
                            hash }
       hash: {}
       id: 5
       hash: {"5"=>1}
       id: 6
       hash: {"6"=>1, "5"=>1}
       id: 7
       hash: {"6"=>1, "7"=>1, "5"=>1}
       id: 8
       hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1}
       id: 9
       hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1}
       id: 10
       => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
            “the best method in
            Ruby...ever”
                                                      - Adam
Street Smarts
  Connect the Dots
Street Smarts
             Connect the Dots
•Get a user
•Get their friends
 •Get their friends-friends (Friends of a
  Friend)

 • Remove current friend IDs and ignored IDs
 • Mutual FOAFs counts (Friends of a Friend) are
   rank
Friend IDs
            Connect the Dots
Get friend’s IDs
 > richard = User.get("Schneems")
 > richard.get_friend_ids
 =>[1, 2] # [john, jane]



Get your friend’s friend IDs
 > friends_of_a_friend_ids = []
 > richard.get_friend_ids do |friend_id|
 > friends_of_a_friend_ids << User.get_someones_friend_ids(friend_id)
 > end.flatten
 =>[3, 4, 5, 6, 7, 3, 4, 5, 8, 9, 10]
   # john and jane’s friend id’s
FOAF IDs
Friend of a Friend Ids
    > friends_of_a_friend_ids = []
    > richard.get_friend_ids do |friend_id|
    > friends_of_a_friend_ids << User.get_someones_friend_ids(friend_id)
    > end.flatten
    =>[3, 4, 5, 6, 7, 3, 4, 5, 8, 9, 10]
      # john and jane’s friend id’s

 What does this give us?

    =>[3,   4, 5,   6, 7,   3, 4, 5,   8, 9, 10]


   (hint, its potential friend IDs)
Remove Bad
                Suggestions
  •Don’t suggest
   •self
     • Pending or accepted friend request
     • Previously ignored potential friends
def not_potential_friend_ids
  @not_potential_friend_ids ||=
    CACHE.get_or("users:not_potential_friends_key:#{self.id}", 24.hours) {
      [self.id] +
      Friendship.where(:user_1_id => self.id).map(&:user_2_id) +
      ignored_potential_friend_ids
    }
end
Put it all Together
Sooooooo... close
 def potential_friend_ids(options = {})
   potential_friend_ids = friends_of_a_friend_ids - not_potential_friend_ids
   potential_ids_with_score = potential_friend_ids.
                              inject({}) {|sorted_id_hash, friend_id|
                                          if sorted_id_hash[friend_id].blank?
                                             sorted_id_hash[friend_id] = 1
                                          else
                                             sorted_id_hash[friend_id] += 1
                                          end
                                          sorted_id_hash }
   sorted_potential_friend_ids = potential_ids_with_score.sort {|x, y|
                                       y.last <=> x.last}.
                                       map(&:first)
   return sorted_potential_friend_ids
 end
Put it all Together
It works!!!!!!
def potential_friends(options = {})
    # TODO add memcached to this call in a production app
    User.where("id in (?)", potential_friend_ids.
         first(options[:limit])).shuffle
end

Boom!!
> User.get(“schneems”).potential_friends(:limit => 2)
> [#<User id: 3 ... >, #<User id: 5 ... >]


                  Goes
                   the
              dynamite
IT WORKS!!
Try It Out
• Sign up on Gowalla
 • http://gowalla.com/join
• Add friends or connect facebook
 • Visit your passport
 • Add and ignore friends to your content
Thats100% Pure
  Crunk Juice
      YEAH!
Questions?




Twitters: @schneems
         github.com/schneems

Mais conteúdo relacionado

Mais procurados

Postgres the best tool you're already using
Postgres the best tool you're already usingPostgres the best tool you're already using
Postgres the best tool you're already usingLiquidPlanner
 
Ruby is Awesome
Ruby is AwesomeRuby is Awesome
Ruby is AwesomeAstrails
 
MySQLConf2009: Taking ActiveRecord to the Next Level
MySQLConf2009: Taking ActiveRecord to the Next LevelMySQLConf2009: Taking ActiveRecord to the Next Level
MySQLConf2009: Taking ActiveRecord to the Next LevelBlythe Dunham
 
Php code for online quiz
Php code for online quizPhp code for online quiz
Php code for online quizhnyb1002
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmdiKlaus
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Suyeol Jeon
 
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB
 
What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)Kerry Buckley
 
Great BigTable and my toys
Great BigTable and my toysGreat BigTable and my toys
Great BigTable and my toysmseki
 
2014 database - course 3 - PHP and MySQL
2014 database - course 3 - PHP and MySQL2014 database - course 3 - PHP and MySQL
2014 database - course 3 - PHP and MySQLHung-yu Lin
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
An (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonAn (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonNicholas Tollervey
 

Mais procurados (18)

Postgres the best tool you're already using
Postgres the best tool you're already usingPostgres the best tool you're already using
Postgres the best tool you're already using
 
Ruby is Awesome
Ruby is AwesomeRuby is Awesome
Ruby is Awesome
 
MySQLConf2009: Taking ActiveRecord to the Next Level
MySQLConf2009: Taking ActiveRecord to the Next LevelMySQLConf2009: Taking ActiveRecord to the Next Level
MySQLConf2009: Taking ActiveRecord to the Next Level
 
Php code for online quiz
Php code for online quizPhp code for online quiz
Php code for online quiz
 
7li7w devcon5
7li7w devcon57li7w devcon5
7li7w devcon5
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmd
 
php plus mysql
php plus mysqlphp plus mysql
php plus mysql
 
PHP 1
PHP 1PHP 1
PHP 1
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
 
PHP Tutorial (funtion)
PHP Tutorial (funtion)PHP Tutorial (funtion)
PHP Tutorial (funtion)
 
What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)
 
Great BigTable and my toys
Great BigTable and my toysGreat BigTable and my toys
Great BigTable and my toys
 
2014 database - course 3 - PHP and MySQL
2014 database - course 3 - PHP and MySQL2014 database - course 3 - PHP and MySQL
2014 database - course 3 - PHP and MySQL
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
Perl object ?
Perl object ?Perl object ?
Perl object ?
 
An (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonAn (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to Python
 
Intro to Redis
Intro to RedisIntro to Redis
Intro to Redis
 

Semelhante a Potential Friend Finder

Adventures in Optimization
Adventures in OptimizationAdventures in Optimization
Adventures in OptimizationDavid Golden
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go ProgrammingLin Yo-An
 
PHP security audits
PHP security auditsPHP security audits
PHP security auditsDamien Seguy
 
Scaling Databases with DBIx::Router
Scaling Databases with DBIx::RouterScaling Databases with DBIx::Router
Scaling Databases with DBIx::RouterPerrin Harkins
 
Ruby's Arrays and Hashes with examples
Ruby's Arrays and Hashes with examplesRuby's Arrays and Hashes with examples
Ruby's Arrays and Hashes with examplesNiranjan Sarade
 
Ruby 入門 第一次就上手
Ruby 入門 第一次就上手Ruby 入門 第一次就上手
Ruby 入門 第一次就上手Wen-Tien Chang
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersGiovanni924
 
Ruby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と HashRuby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と Hashhigaki
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosEdgar Suarez
 
第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 DatasourceKaz Watanabe
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a bossgsterndale
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackVic Metcalfe
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redisjimbojsb
 
Dynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship groupDynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship groupReuven Lerner
 
Fazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchFazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchPedro Franceschi
 

Semelhante a Potential Friend Finder (20)

Adventures in Optimization
Adventures in OptimizationAdventures in Optimization
Adventures in Optimization
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go Programming
 
PHP security audits
PHP security auditsPHP security audits
PHP security audits
 
Scaling Databases with DBIx::Router
Scaling Databases with DBIx::RouterScaling Databases with DBIx::Router
Scaling Databases with DBIx::Router
 
Ruby's Arrays and Hashes with examples
Ruby's Arrays and Hashes with examplesRuby's Arrays and Hashes with examples
Ruby's Arrays and Hashes with examples
 
P3 2018 python_regexes
P3 2018 python_regexesP3 2018 python_regexes
P3 2018 python_regexes
 
Ruby 入門 第一次就上手
Ruby 入門 第一次就上手Ruby 入門 第一次就上手
Ruby 入門 第一次就上手
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammers
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
Ruby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と HashRuby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と Hash
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutos
 
Substitution Cipher
Substitution CipherSubstitution Cipher
Substitution Cipher
 
第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
 
DataMapper
DataMapperDataMapper
DataMapper
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: Hack
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
 
Dynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship groupDynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship group
 
Fazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchFazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearch
 
My First Ruby
My First RubyMy First Ruby
My First Ruby
 

Mais de Richard Schneeman

Scaling the Web: Databases & NoSQL
Scaling the Web: Databases & NoSQLScaling the Web: Databases & NoSQL
Scaling the Web: Databases & NoSQLRichard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 8
Rails 3 Beginner to Builder 2011 Week 8Rails 3 Beginner to Builder 2011 Week 8
Rails 3 Beginner to Builder 2011 Week 8Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 6
Rails 3 Beginner to Builder 2011 Week 6Rails 3 Beginner to Builder 2011 Week 6
Rails 3 Beginner to Builder 2011 Week 6Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 5
Rails 3 Beginner to Builder 2011 Week 5Rails 3 Beginner to Builder 2011 Week 5
Rails 3 Beginner to Builder 2011 Week 5Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 4
Rails 3 Beginner to Builder 2011 Week 4Rails 3 Beginner to Builder 2011 Week 4
Rails 3 Beginner to Builder 2011 Week 4Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 3
Rails 3 Beginner to Builder 2011 Week 3Rails 3 Beginner to Builder 2011 Week 3
Rails 3 Beginner to Builder 2011 Week 3Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 2
Rails 3 Beginner to Builder 2011 Week 2Rails 3 Beginner to Builder 2011 Week 2
Rails 3 Beginner to Builder 2011 Week 2Richard Schneeman
 
Rails 3 Beginner to Builder 2011 Week 1
Rails 3 Beginner to Builder 2011 Week 1Rails 3 Beginner to Builder 2011 Week 1
Rails 3 Beginner to Builder 2011 Week 1Richard Schneeman
 
Rails3 Summer of Code 2010 - Week 6
Rails3 Summer of Code 2010 - Week 6Rails3 Summer of Code 2010 - Week 6
Rails3 Summer of Code 2010 - Week 6Richard Schneeman
 
Rails3 Summer of Code 2010- Week 5
Rails3 Summer of Code 2010- Week 5Rails3 Summer of Code 2010- Week 5
Rails3 Summer of Code 2010- Week 5Richard Schneeman
 

Mais de Richard Schneeman (13)

Scaling the Web: Databases & NoSQL
Scaling the Web: Databases & NoSQLScaling the Web: Databases & NoSQL
Scaling the Web: Databases & NoSQL
 
Rails 3 Beginner to Builder 2011 Week 8
Rails 3 Beginner to Builder 2011 Week 8Rails 3 Beginner to Builder 2011 Week 8
Rails 3 Beginner to Builder 2011 Week 8
 
Rails 3 Beginner to Builder 2011 Week 6
Rails 3 Beginner to Builder 2011 Week 6Rails 3 Beginner to Builder 2011 Week 6
Rails 3 Beginner to Builder 2011 Week 6
 
Rails 3 Beginner to Builder 2011 Week 5
Rails 3 Beginner to Builder 2011 Week 5Rails 3 Beginner to Builder 2011 Week 5
Rails 3 Beginner to Builder 2011 Week 5
 
Rails 3 Beginner to Builder 2011 Week 4
Rails 3 Beginner to Builder 2011 Week 4Rails 3 Beginner to Builder 2011 Week 4
Rails 3 Beginner to Builder 2011 Week 4
 
Rails 3 Beginner to Builder 2011 Week 3
Rails 3 Beginner to Builder 2011 Week 3Rails 3 Beginner to Builder 2011 Week 3
Rails 3 Beginner to Builder 2011 Week 3
 
Rails 3 Beginner to Builder 2011 Week 2
Rails 3 Beginner to Builder 2011 Week 2Rails 3 Beginner to Builder 2011 Week 2
Rails 3 Beginner to Builder 2011 Week 2
 
Rails 3 Beginner to Builder 2011 Week 1
Rails 3 Beginner to Builder 2011 Week 1Rails 3 Beginner to Builder 2011 Week 1
Rails 3 Beginner to Builder 2011 Week 1
 
Rails3 Summer of Code 2010 - Week 6
Rails3 Summer of Code 2010 - Week 6Rails3 Summer of Code 2010 - Week 6
Rails3 Summer of Code 2010 - Week 6
 
Rails3 Summer of Code 2010- Week 5
Rails3 Summer of Code 2010- Week 5Rails3 Summer of Code 2010- Week 5
Rails3 Summer of Code 2010- Week 5
 
UT on Rails3 2010- Week 4
UT on Rails3 2010- Week 4 UT on Rails3 2010- Week 4
UT on Rails3 2010- Week 4
 
UT on Rails3 2010- Week 2
UT on Rails3 2010- Week 2UT on Rails3 2010- Week 2
UT on Rails3 2010- Week 2
 
UT on Rails3 2010- Week 1
UT on Rails3 2010- Week 1UT on Rails3 2010- Week 1
UT on Rails3 2010- Week 1
 

Último

[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfAarwolf Industries LLC
 
QMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfQMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfROWELL MARQUINA
 
All These Sophisticated Attacks, Can We Really Detect Them - PDF
All These Sophisticated Attacks, Can We Really Detect Them - PDFAll These Sophisticated Attacks, Can We Really Detect Them - PDF
All These Sophisticated Attacks, Can We Really Detect Them - PDFMichael Gough
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...BookNet Canada
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...amber724300
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentMahmoud Rabie
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...Karmanjay Verma
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Accelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessAccelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessWSO2
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
WomenInAutomation2024: AI and Automation for eveyone
WomenInAutomation2024: AI and Automation for eveyoneWomenInAutomation2024: AI and Automation for eveyone
WomenInAutomation2024: AI and Automation for eveyoneUiPathCommunity
 

Último (20)

[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdf
 
QMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdfQMMS Lesson 2 - Using MS Excel Formula.pdf
QMMS Lesson 2 - Using MS Excel Formula.pdf
 
All These Sophisticated Attacks, Can We Really Detect Them - PDF
All These Sophisticated Attacks, Can We Really Detect Them - PDFAll These Sophisticated Attacks, Can We Really Detect Them - PDF
All These Sophisticated Attacks, Can We Really Detect Them - PDF
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career Development
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Accelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessAccelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with Platformless
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
WomenInAutomation2024: AI and Automation for eveyone
WomenInAutomation2024: AI and Automation for eveyoneWomenInAutomation2024: AI and Automation for eveyone
WomenInAutomation2024: AI and Automation for eveyone
 

Potential Friend Finder

  • 1. How Richard Found Friends Richard Schneeman @schneems I hack rubies for @gowalla
  • 2. Meet Richard •Richard needs more friends •Richard has one or more friends on our network •We can help him find more!
  • 3. def potential_friend •Someone who Richard likely knows and wants to “friend” on a service (e.g. Gowalla)
  • 4. def mutual_friend •When two users have the same friend, it is a mutual friend
  • 8. Richard’s Friends John Jane John’s Friends
  • 9. Richard’s Friends John Jane John’s Friends Jane’s Friends
  • 10. Richard’s Friends John Jane John’s Friends Jane’s Friends
  • 11. Richard’s Friends John Jane John’s Friends Jane’s Friends } Mutual Friends
  • 12. Friends of Friends •Friends of friends are all potential friends •People are more likely to “friend” another user if they are a “friend of a friend” •Mutual friend numbers provide a ranking system
  • 13. Friends of Friends John Doe’s Jane Doe’s Friends Friends
  • 14. Friends of Friends John Doe’s Jane Doe’s Friends Friends
  • 15. Friends of Friends John Doe’s Jane Doe’s Friends Friends +1 +1
  • 16. Friends of Friends John Doe’s Jane Doe’s Friends Friends +1 +2 +1
  • 17. Friends of Friends John Doe’s Jane Doe’s Friends Friends Justin Beiber’s Friends
  • 18. Friends of Friends John Doe’s Jane Doe’s Friends Friends +2 +1 +1 +2+3+2 +1 Justin Beiber’s Friends
  • 19. How do we do that in our App? •Memcache •Redis •Street Smarts (Making it rain friendships)
  • 20. Memcache •Key value store (NOSQL) •Holds ruby objects> CACHE.set("foo", "bar")=> nil •Extremely fast > CACHE.get("foo") => "bar" •volatile •Used to (mem)cache database queries
  • 21. Memcache Key Value Store > CACHE.set("foo", "bar") > CACHE.get("foo") => "bar" > user = User.where(:username => “Schneems”).first > CACHE.set("foo", user) > CACHE.get("foo") => #<User id: 263595 ... > Marshals Ruby Objects (like a boss)
  • 23. Memcache Pattern get||Set class Memcached def get_or(key, timeout=0, marshal=true, &block) get(key, marshal) rescue Memcached::NotFound => e if block_given? value = block.call set(key, value, timeout, marshal) rescue nil value else raise e end end end gets the value || makes the query and sets the cache
  • 24. Memcache - Speed Tips •Cache frequently queried objects (get users) class User < ActiveRecord::Base def self.get(username) CACHE.get_or("user:#{username}") do User.where(:username => "#{username}").first end end end >> User.get("schneems") => #<User id: 263595 ... >
  • 25. Memcache: (I wanna Go Fast) # Database > Benchmark.measure do User.where(:username => "schneems").first end.real => 0.09 s # Memcache > Benchmark.measure do User.get("schneems") end.real => 0.0009 s oh yeah
  • 26. Memcache - Speed Tips •Cache expensive queries (Friend IDs) class User < ActiveRecord::Base def get_friend_ids CACHE.get_or("friend_ids:#{self.id}") do friends = Friendships.where(:user_1_id => self.id) friends.map {|friend| friend.user_2_id } end end end >> u = User.get("schneems") >> u.get_friend_ids => [1,2,3,...]
  • 27. Memcache • Key/Value store (NOSQL) • Holds ruby objects • Extremely fast • volatile • Can be used to cache expensive database queries > CACHE.set("foo", "bar")=> nil > CACHE.get("foo") => "bar"
  • 28. Redis •Key value store (NOSQL: yes another one) •does NOT store ruby objects...boo :’ ( •Native data structures...yay :) •pretty-darn fast •non-volatile!!!!!!!!!!
  • 29. Redis keys & values & stores > REDIS.set("chunky", "bacon") => "OK" > REDIS.get("chunky") => "bacon" http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
  • 30. Redis - Datatypes • String • Set (collection of strings with no duplicates) • Sorted Set • List (sorted collection of strings like and array) http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
  • 31. Redis - Lists keys & values & stores > REDIS.lpush("lists:are:like:an:array", 1) => 1 > REDIS.lpush("lists:are:like:an:array", 2) => 2 > REDIS.lpush("lists:are:like:an:array", 3) => 3 > REDIS.lrange("lists:are:like:an:array", 0, -1) => ["3", "2", "1"] > REDIS.lrange("lists:are:like:an:array", 0, -1).map(&:to_i) => [3, 2, 1] http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
  • 32. Redis - Lists Store “ignored” potential friends def ignore_potential_friend(friend_id) REDIS.lpush(ignore_facebook_friend_key, friend_id) end Retrieve array of ignored IDs def ignored_potential_friend_ids REDIS.lrange(not_potential_friend_ids_key, 0, -1).map(&:to_i) end
  • 33. Redis - Recap •Key value store (yes another one) •does NOT store ruby objects...boo :’ ( •Native data structures...yay :) •pretty-darn fast •non-volatile!!!!!!!!!!
  • 34. Redis - Extra Getting Started Credit http://jimneath.org/2011/03/24/using-redis-with-ruby- on-rails.html Resque Background jobs with Redis (and style) https://github.com/defunkt/resque
  • 35. Street Smarts •Ruby array ‘tricks’ •Connecting the dots Memcache Redis & Ruby Potential Friends
  • 36. Street Smarts Ruby array Manipulation Intersection ( &) > [1,2,3] & [3,4,5] => [3] > [1,2,3,4] & [3,4,5] => [3,4] Difference ( -) > [1,2,3] - [3,4,5] => [1,2,4,5] > [1,2,3,4] - [3,4,5] => [1,2,5]
  • 37. Street Smarts Ruby array Manipulation Concatenation ( +) > [1,2] + [3,4,5] => [1,2,3,4,5]
  • 38. Street Smarts Ruby array Manipulation inject - turning arrays into other stuff [5,6,7,8,9,10].inject(0) {|sum, n| sum + n } => 45
  • 39. Street Smarts Ruby array Manipulation inject - turning arrays into other stuff [5,6,7,8,9,10].inject(0) {|sum, n| sum + n } => 45 inject - build hashes from arrays > array = [5,6,7,8,9,10] > array.inject({}) {|hash, id| hash[id.to_s] = 1; hash } => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 40. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 41. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 42. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 43. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 44. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 45. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 46. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 47. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1}
  • 48. inject - build hashes from arrays > array.inject({}) {|hash, id| puts "hash: #{hash.inspect}" puts "id: #{id}" hash[id.to_s] = 1; hash } hash: {} id: 5 hash: {"5"=>1} id: 6 hash: {"6"=>1, "5"=>1} id: 7 hash: {"6"=>1, "7"=>1, "5"=>1} id: 8 hash: {"6"=>1, "7"=>1, "8"=>1, "5"=>1} id: 9 hash: {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "5"=>1} id: 10 => {"6"=>1, "7"=>1, "8"=>1, "9"=>1, "10"=>1, "5"=>1} “the best method in Ruby...ever” - Adam
  • 49. Street Smarts Connect the Dots
  • 50. Street Smarts Connect the Dots •Get a user •Get their friends •Get their friends-friends (Friends of a Friend) • Remove current friend IDs and ignored IDs • Mutual FOAFs counts (Friends of a Friend) are rank
  • 51. Friend IDs Connect the Dots Get friend’s IDs > richard = User.get("Schneems") > richard.get_friend_ids =>[1, 2] # [john, jane] Get your friend’s friend IDs > friends_of_a_friend_ids = [] > richard.get_friend_ids do |friend_id| > friends_of_a_friend_ids << User.get_someones_friend_ids(friend_id) > end.flatten =>[3, 4, 5, 6, 7, 3, 4, 5, 8, 9, 10] # john and jane’s friend id’s
  • 52. FOAF IDs Friend of a Friend Ids > friends_of_a_friend_ids = [] > richard.get_friend_ids do |friend_id| > friends_of_a_friend_ids << User.get_someones_friend_ids(friend_id) > end.flatten =>[3, 4, 5, 6, 7, 3, 4, 5, 8, 9, 10] # john and jane’s friend id’s What does this give us? =>[3, 4, 5, 6, 7, 3, 4, 5, 8, 9, 10] (hint, its potential friend IDs)
  • 53. Remove Bad Suggestions •Don’t suggest •self • Pending or accepted friend request • Previously ignored potential friends def not_potential_friend_ids @not_potential_friend_ids ||= CACHE.get_or("users:not_potential_friends_key:#{self.id}", 24.hours) { [self.id] + Friendship.where(:user_1_id => self.id).map(&:user_2_id) + ignored_potential_friend_ids } end
  • 54. Put it all Together Sooooooo... close def potential_friend_ids(options = {}) potential_friend_ids = friends_of_a_friend_ids - not_potential_friend_ids potential_ids_with_score = potential_friend_ids. inject({}) {|sorted_id_hash, friend_id| if sorted_id_hash[friend_id].blank? sorted_id_hash[friend_id] = 1 else sorted_id_hash[friend_id] += 1 end sorted_id_hash } sorted_potential_friend_ids = potential_ids_with_score.sort {|x, y| y.last <=> x.last}. map(&:first) return sorted_potential_friend_ids end
  • 55. Put it all Together It works!!!!!! def potential_friends(options = {}) # TODO add memcached to this call in a production app User.where("id in (?)", potential_friend_ids. first(options[:limit])).shuffle end Boom!! > User.get(“schneems”).potential_friends(:limit => 2) > [#<User id: 3 ... >, #<User id: 5 ... >] Goes the dynamite
  • 57. Try It Out • Sign up on Gowalla • http://gowalla.com/join • Add friends or connect facebook • Visit your passport • Add and ignore friends to your content
  • 58. Thats100% Pure Crunk Juice YEAH!
  • 59. Questions? Twitters: @schneems github.com/schneems

Notas do Editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n