lauantai 31. maaliskuuta 2012

Facebook-verkostojen visualisointi

SPOILER: tämä postaus käsittelee teknistä sanastoa.

Innostuin tällä viikolla tutkimaan miten Facebook-verkostoja olisi mahdollista kerätä ja visualisoida vastaavalla tavalla kuten olen aikaisemmin visualisoinut Twitter-verkostoja sekä keitä @TuomasEnbuske seuraa. Enemmän tai vähemmän tunnetusti Facebook on kitsaampi jakamaan tietojaan Graph-rajapintansa kautta kuin mitä Twitter oman rajapintansa kautta, mutta rohkaistuin kuitenkin yrittämään tehtyäni ensin Olli Parviaisen kanssa kansanedustajien kaveruusverkoston sekä nähtyäni miten Jens Finnäs oli onnistunut tekemään vastaavanlaisen toteutuksen Ruotsin parlamentista.

Graph-rajapinta


Facebook:lla on siis olemassa Graph-niminen rajapinta, joka mahdollistaa Facebook-datan käsittelyn koneellisesti. Lähinnä rajapinta on varmasti tarkoitettu erilaisille Facebook-applikaatioille, mutta sitä on mahdollista käyttää myös muuten. Yksinkertainen Graph-rajapintakysely, joka palauttaa halutun käyttäjän (tässä tapauksessa allekirjoittaneen) tiedot (kuten ID, sukupuoli, nimi, jne.) voidaan suorittaa syöttämällä seuraava osoite selaimeen:

graph.facebook.com/teelmo.

Rajapintaa voidaan kutsua yhtälailla käyttäjän käyttäjänimellä kuin Facebook:n käyttäjä-ID-arvolla. Toisin sanoen kysely:

graph.facebook.com/635279474,

tuottaa saman vastauksen. Tiedot ovat haettavissa Graph-rajapinnan kautta kenestä tahansa Facebook-profiilista huolimatta siitä miten suljettu tai avoin profiili on. Rajapinnalta on mahdollista kysyä myös monia muita asioita, mutta esimerkiksi satunnaisen käyttäjän Facebook-kavereiden hakeminen ei ole mahdollista edes vaikka olisit kyseisen käyttäjän kaveri. Muiden kuin itsensä kavereiden hakeminen onnistuu rajapinnan kautta jos käyttäjä on sallinut tietojensa jakamisen applikaatiolle, jonka ylläpitäjä olet. Omat Facebook-kaverit rajapinnan kautta saa haettua.

Python + MongoDB = voitto


Kuten edellä näytettiin on Graph-rajapintaa mahdollista selata käsipelillä selaimen avulla, mutta käsiteltäessä suurempia datajoukkoja tulee tiedon keräämisestä tällä tavoin raskasta. Näin ollen erinäiset ohjelmointikielet ja niillä rakennetut scriptit eli lyhyet kertaalleen ajettavat ohjelmakoodit tulevat apuun. Käytetyllä ohjelmointikielellä ei ole suurta merkitystä vaan valinta kannattaa tehdä sen pohjalta, joka on itselle tutuin ja luontevin. Hyviä vaihtoehtoja kuitenkin ovat ainakin Python, Ruby ja Facebook:n tapauksessa etenkin PHP, koska suurin osa Facebook:n koodiesimerkeistä on kirjoitettu sillä. Itse valitsin kuitenkin Pythonin, koska halusin jatkojalostaa omaa Python osaamistani.

Pythonille löytyy useampia Facebook Graph API -kirjastoja, mutta ainakin pyFaceGraph-nimisen kirjaston avulla Graph-rajapinnan käyttö on todella yksinkertaista. Tässä yksinkertainen koodin pätkä, joka hakee käyttäjän tiedot kirjaston avulla jos käyttäjän tietoja ei ole jo aikaisemmin haettu ja tallennettu tietokantaan.

>>> from facegraph import Graph
>>> g = Graph()
>>> ...
>>> username = 'teelmo'
>>> # Check that username is not already in MongoDB
>>> if not users.find({"data.username": fusername}).count():
>>>    user = g[username]()
>>>    print user.id
'635279474'

Tietojen tallentamisessa hyödynsin MongoDB:tä, joka on NoSQL-tietokanta. MongoDB soveltuu käytettäväksi tämänkaltaisissa scripteissä, jotka hakevat tietoa netistä, koska tiedon eheydestä eikä rakenteesta tarvitse välittää samalla tavalla kuin käytettäessä esimerkiksi MySQL:ää tai muuta SQL-pohjaista tietokannanhallintajärjestelmää. MongoDB hyödyntää tiedon tallentamisessa JSON-formaattia, joka on myös formaatti, jossa Graph-rajapinta palauttaa hakutulokset.

Kuvassa 1 nähdään miten scripti hakee annettujen käyttäjien tietoja Graph-rajapinnalta. Tässä tapauksessa suurin osa haettavista käyttäjistä on jo aikaisemmin noudettu lokaaliin tietokantaan, mutta yhden käyttäjän osalta tiedot haetaan Graph-rajapinnasta.

Pythonilla ja MongoDB:llä toteutettu keräin, joka hakee annettujen käyttäjien tiedot Facebookin Graph-rajapinnasta. (Kuva 1)
Facebook:n Graph API ei rajoita tietojen hakemista samalla tavalla kuin Twitter (150 pyyntöä tunnissa), mutta satunnaisesti joitain virheitä esiintyy. Ongelmatilanteissa auttaa kun tiedot tallennetaan lokaalisti MongoDB:hen eikä tietojen hakemista tarvitse siten aloittaa ongelmatilanteissa alusta.

Käyttäjien tiedot kyllä, mutta miten yhteydet?


Graph-rajapinnan tarjoamat toiminnallisuudet on listattu täällä. Rajapinnan avulla saadaan siis kysyttyä suoraan mm. käyttäjien, tapahtumien ja sivujen tietoja. Käyttäjien välisiä yhteyksiä, tapahtumaan osallistujia tai sivujen tykkääjiä ei rajapinnan perustoiminnallisuuksilla kuitenkaan saa haettua.

Apuun tulee kuitenkin Graph-rajapintaa laajentava Facebook Query Language (FQL). FQL mahdollistaa Graph-rajapinnan kautta saatavien tietojen hakemisen SQL:n kaltaisella kyselykielellä. Esimerkiksi Facebook:n käyttäjä-ID:tä vastaava käyttäjänimi on mahdollista hakea seuraavalla kyselyllä:

SELECT username FROM user WHERE uid = 635279474

Käyttäjien välisten kaveruussuhteiden kyseleminen on mahdollista friend-taulusta. On huomioitavaa, että kaveruussuhteita on mahdollista kysyä myös sellaisten käyttäjien välillä, jotka muuten ovat piilottaneet profiilinsa. FQL:ää on mahdollista kokeilla erityisellä Graph API Explorer -työkalulla. FQL:n käyttäminen edellyttää OAuth-tunnistautumista ja ns. "Access token" täytyy välittää kyselyiden mukana.

Toteutin myös yhteyksien hakemisen Python-scriptillä. Apuna käytin Pythonille löytyvää requests-kirjastoa. Tässä yksinkertaisuudessaan ja lyhykäisyydessään FQL-kyselyn toteuttava koodinpätkä:

>>> import requests
>>> ...
>>> fql_query = "SELECT uid2 FROM friend WHERE uid1 = 635279474 and uid2 = %d" % uid2
>>> fql = "/fql?q=%s&access_token=%s" % (fql_query, access_token)
>>> try:
>>>    r = requests.get(domain + fql)
>>> except:
>>>    print "Error occured"


FQL-kysely palauttaa ne käyttäjä-ID-arvot, jotka täsmäävät annettuun hakuun. Eli hakiessani olenko kaveri käyttäjien A, B ja C kanssa palauttaa Facebook niiden käyttäjien ID:t, joiden kanssa haetuista olen kaveri.

Tulokset kirjoitin .gexf-muodossa ja visualisoinnin tein Gephi-nimisellä verkostojen visualisointiohjelmalla. Gephi:n käyttöön en mene tässä sen syvällisemmin, koska olen käsitellyt sitä jo aiemmin tässä blogissa ja tyydynkin vain viittaamaan Olli Parviaiseen luomiin ohjeistuksiin.

Summa summarum


Yhteenvetona voitaneen todeta, että Facebook:sta on mahdollista muodostaa kaveruusverkostoja vastaavasti kuin aikaisemmin olen näyttänyt Twitter:stä. Facebook:n kohdalla joutuu hieman enemmän tekemään käsityötä datan keräämisessä, mutta lopputulos on täysin vastaava. Erona Twitter-verkostoihin on, että Facebook:sta kerätyistä kaveruusverkostoista muodostuu paljon rypästeisempiä (Kuva 2). Eri ryhmät kuten lapsuuden ystävät, koulukaverit, työkaverit ja sukulaiset ovat hyvin vähän tekemisissä toistensa kanssa, mutta ovat linkittyneet keskenään hyvin paljon.

Facebook-kaveriverkostoni. Eri ryhmät erottuvat toisistaan erittäin selkeästi. Solmuja verkostossa on 206 ja yhteyksiä 1878. (Kuva 2)
Twitter:ssä taas ihmiset ovat enemmän verkostoituneet keskenään yli sosiaalisten tai fyysisten rajojen (Kuva 3). Twitter:n demografia poikkeaa toki hyvin paljon Facebook:sta, mutta mielestäni tämä kertoo, että Twitter:ssä seurataan kiinnostavia henkilöitä ja itse asiaa, joka johtaa samoista asioista kiinnostuneiden ihmisten tiheisiin verkostoihin. Toisaalta voidaan vetää myös se johtopäätös, että julistan Twitter:ssä vain yhden aihealueen ilosanomaa ja jos aihealueita olisi useampia nähtäisiin näistä eri aihealueista kiinnostuneet ihmiset omina ryppäinään.

Twitter-seuraajaverkostoni. Ihmiset ovat verkostoituneet keskenään hyvin tiheästi. Solmuja verkostossa 149 ja yhteyksiä 1209. (Kuva 3)
Voidaan kuitenkin tehdä sivistynyt arvaus, että Facebook:ssa seurataan ihmisiä, jotka ovat tuttuja fyysisestä maailmasta kun taas Twitter:ssä seurataan ihmisiä, jotka ovat kiinnostavia. Tässä toki kyseessä vain yhden ihmisen Facebook-kaverit ja Twitter-seuraajat, joten kovin pitkälle meneviä johtopäätöksiä ei voida tehdä, mutta olen havainnut samankaltaisen trendin esiintymisen myös muissa testitapauksissa.

Stay tuned!

"Ryömin juuri kaikkia @TuomasEnbuske:n seuraajia Keitä me kaikki ollaan Seuraavaksi @alexstubb Siinä taitaakin olla kaikki suom. Twitteristit" - https://twitter.com/#!/teelmo/status/185680267548168192

6 kommenttia:

  1. Mahtavaa! Kuinka pitkä matka siihen, että tuollaisen verkostokaivelun pystyisi tuotteistamaan laiskan mutta uteliaan netin käyttäjän "syötä tunnari tähän ja katsele tiimalasia" - palveluksi?

    VastaaPoista
  2. Tai katsele rantapalloa..

    Niin, tuon kaiveluosuuden tuotteistaminen olisi tällaiselle yksittäiselle datakohteelle kuten Facebook ja yksittäiselle käyttötapaukselle kuten kaveriverkosto melko helppoa. Tällä hetkelläkin toteutus toimii paina nappulaa ja nauti elämästä -periaatteella, mutta toki terminaaliympäristössä ja vain lokaalilla koneella, mutta esimerkiksi verkkopalvelun, jonka kautta toteutusta olisi mahdollista ohjata, prototyypin toteuttaminen olisi suhteellisen yksinkertaista (1-2 työpäivän panos).

    Yleismaailmallisemman verkostonkaiveluapplikaation kannalta asia on toki paljon paljon haastavampaa. Erilaisten kaivelijoiden osalta kannattaa tarkistaa (https://scraperwiki.com/).

    Analyysin osalta automatisointiin ei tällä hetkellä varmaan ole (ainakaan) open source -työkaluja.

    ps. Facebook:n osalta tulee kaivelussa ottaa huomioon Facebook:n (tiukat) käyttöehdot (joita toki itse en ole lukenut).

    VastaaPoista
  3. Ymmärsinkö oikein: käytät Facebookia, mutta et ole lukenut käyttöehtoja?

    VastaaPoista
  4. Tuossahan syntyy henkilörekisteri. Missäs on rekisteriseloste?

    VastaaPoista
  5. Hei Jussi,

    voitko tarkentaa minkä perusteella näet tässä syntyvän rekisteriselostetta vaativan henkilörekisterin: http://www.finlex.fi/fi/laki/ajantasa/1999/19990523

    kun käyttäjistä tallennettavat tiedot ovat kaikki ihmisen itse itsestään julkiseksi saattamia ja saatavissa Facebookin rajapinnan kautta.

    VastaaPoista