www.autentia.com
GeoSentimentZ
domingo 2 de junio de 13
www.autentia.com
Who’s that guy
domingo 2 de junio de 13
www.autentia.com
Want to track something?
Probably people is talking
about it on the Web and
social media
domingo 2 de junio de 13
www.autentia.com
Are you trendy?
domingo 2 de junio de 13
www.autentia.com
Are you trendy?
domingo 2 de junio de 13
www.autentia.com
New ways to measure
TPS: Tweets Per Second
domingo 2 de junio de 13
www.autentia.com
New ways to measure
TPS: Tweets Per Second
domingo 2 de junio de 13
www.autentia.com
New ways to measure
TPS: Tweets Per Second
domingo 2 de junio de 13
www.autentia.com
New ways to measure
TPS: Tweets Per Second
domingo 2 de junio de 13
www.autentia.com
How influential are you?
domingo 2 de junio de 13
www.autentia.com
New tools to measure
Built on APIs to get data
Built on APIs to represent data
domingo 2 de junio de 13
www.autentia.com
The Building blocks:
The APIs
domingo 2 de junio de 13
www.autentia.com
Google Maps API
Well known interface
Gives different layers
- Map
- Terrain
- Satellite
Place Points Of Interest
Group POIs
POI metadata
domingo 2 de junio de 13
www.autentia.com
Google Maps API use
<script	
  src="http://maps.google.com/maps/api/js?sensor=false"></script>
var	
  map;
function	
  initialize()	
  {
	
  	
  var	
  center	
  =	
  new	
  google.maps.LatLng(50,	
  20);
	
  	
  map	
  =	
  new	
  google.maps.Map(document.getElementById('map'),	
  {
	
  	
  	
  	
  zoom:	
  3,
	
  	
  	
  	
  center:	
  center,
	
  	
  	
  	
  mapTypeId:	
  google.maps.MapTypeId.ROADMAP
	
  	
  });
}
google.maps.event.addDomListener(window,	
  'load',	
  initialize);
domingo 2 de junio de 13
www.autentia.com
Google Maps API use
<script	
  src="http://maps.google.com/maps/api/js?sensor=false"></script>
var	
  map;
function	
  initialize()	
  {
	
  	
  var	
  center	
  =	
  new	
  google.maps.LatLng(50,	
  20);
	
  	
  map	
  =	
  new	
  google.maps.Map(document.getElementById('map'),	
  {
	
  	
  	
  	
  zoom:	
  3,
	
  	
  	
  	
  center:	
  center,
	
  	
  	
  	
  mapTypeId:	
  google.maps.MapTypeId.ROADMAP
	
  	
  });
}
google.maps.event.addDomListener(window,	
  'load',	
  initialize);
<div id="map-container">
<div id="map"></div>
</div>
domingo 2 de junio de 13
www.autentia.com
Google Maps API use
function	
  callEvents(){
	
   var	
  searchQuery	
  =	
  $('#searchQuery').value;
	
   $.ajax({
	
   	
   url:	
  '/sentimentz/pois/'	
  +	
  encodeURIComponent(searchQuery),
	
   	
   type:	
  'GET',
	
   	
   contentType:	
  'application/json',
	
   	
   success:	
  function(data){
	
   	
   	
   setTimeout(function(){	
  putEvents(data)},	
  500);
	
   	
   },
	
   	
   error:	
  function(data,	
  status,	
  er){
	
   	
   	
   //....
	
   	
   }
	
   });
}
domingo 2 de junio de 13
www.autentia.com
Google Maps API use
function	
  callEvents(){
	
   var	
  searchQuery	
  =	
  $('#searchQuery').value;
	
   $.ajax({
	
   	
   url:	
  '/sentimentz/pois/'	
  +	
  encodeURIComponent(searchQuery),
	
   	
   type:	
  'GET',
	
   	
   contentType:	
  'application/json',
	
   	
   success:	
  function(data){
	
   	
   	
   setTimeout(function(){	
  putEvents(data)},	
  500);
	
   	
   },
	
   	
   error:	
  function(data,	
  status,	
  er){
	
   	
   	
   //....
	
   	
   }
	
   });
}
[
	
  	
  	
  {
	
  	
  	
  	
  	
  	
  "rate":0,
	
  	
  	
  	
  	
  	
  "msg":"Muy	
  buena	
  exposición	
  	
  sobre	
  API	
  business	
  
model	
  #APIDays",
	
  	
  	
  	
  	
  	
  "location":{
	
  	
  	
  	
  	
  	
  	
  	
  	
  "latitude":40.44614387,
	
  	
  	
  	
  	
  	
  	
  	
  	
  "longitude":-­‐3.67365923
	
  	
  	
  	
  	
  	
  },
	
  	
  	
  	
  	
  	
  "id":340414678016593920,
	
  	
  	
  	
  	
  	
  "createAt":1369996158000
	
  	
  	
  }
]
domingo 2 de junio de 13
www.autentia.com
Google Maps API use
function	
  putEvents(events){
	
   var	
  bounds	
  =	
  new	
  google.maps.LatLngBounds();
	
   var	
  markers	
  =	
  [];
	
   document.getElementById("totalGeoTweets").innerHTML	
  =	
  events.length;
	
  	
  	
  	
  for	
  (var	
  i	
  =	
  0;	
  i	
  <	
  events.length;	
  i++)	
  {
	
  	
  	
  	
  	
  	
  var	
  event	
  =	
  events[i];
	
  	
  	
  	
  	
  	
  var	
  latLng	
  =	
  new	
  google.maps.LatLng(event.location.latitude,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  event.location.longitude);
	
  	
  	
  	
  	
  	
  bounds.extend(latLng);
	
  	
  	
  	
  	
  	
  var	
  marker	
  =	
  new	
  google.maps.Marker({
	
  	
  	
  	
  	
  	
  	
  	
  position:	
  latLng,
	
  	
  	
  	
  	
  	
  	
  	
  map:	
  map,
	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  	
  	
  markers.push(marker);
	
  	
  	
  	
  }
	
   map.fitBounds(bounds);
	
  	
  	
  	
  var	
  markerCluster	
  =	
  new	
  MarkerClusterer(map,	
  markers);
}
domingo 2 de junio de 13
www.autentia.com
The Source: twitter
An open window to shout your
thougths...
... that everyone can listen
#hashtags
@users
queryStrings
Geolocalized
domingo 2 de junio de 13
www.autentia.com
Info contained in a tweet
http://www.geekosystem.com/tweet-diagram/
domingo 2 de junio de 13
www.autentia.com
Twitter: The search API
domingo 2 de junio de 13
www.autentia.com
Twitter: The search API
<dependency>
	 <groupId>org.twitter4j</groupId>
	 <artifactId>twitter4j-core</artifactId>
	 <version>3.0.3</version>
</dependency>
domingo 2 de junio de 13
www.autentia.com
Twitter: The search API
<dependency>
	 <groupId>org.twitter4j</groupId>
	 <artifactId>twitter4j-core</artifactId>
	 <version>3.0.3</version>
</dependency>
public	
  List<Event>	
  retrieveAllTweetsByQuery(String	
  hashtag)
	
   	
   throws	
  TwitterException,	
  MalformedURLException	
  {
	
   Twitter	
  twitter	
  =	
  TwitterFactory.getInstance();
	
   Query	
  query	
  =	
  new	
  Query(hashtag);
	
   QueryResult	
  result;
	
   List<Status>	
  tweets	
  =	
  new	
  ArrayList<Status>();
	
   do	
  {
	
   	
   result	
  =	
  twitter.search(query);
	
   	
   tweets.addAll(result.getTweets());
	
   }	
  while	
  ((query	
  =	
  result.nextQuery())	
  !=	
  null);
}	
  
domingo 2 de junio de 13
www.autentia.com
Twitter: The search API
public	
  List<Event>	
  retrieveAllTweetsByQuery(String	
  hashtag)
	
   	
   throws	
  TwitterException,	
  MalformedURLException	
  {
	
   Twitter	
  twitter	
  =	
  getTwitterAccessor();
	
   Query	
  query	
  =	
  new	
  Query(hashtag);
	
   QueryResult	
  result;
	
   List<Status>	
  tweets	
  =	
  new	
  ArrayList<Status>();
	
   do	
  {
	
   	
   result	
  =	
  twitter.search(query);
	
   	
   tweets.addAll(result.getTweets());
	
   }	
  while	
  ((query	
  =	
  result.nextQuery())	
  !=	
  null);
}	
  
domingo 2 de junio de 13
www.autentia.com
What others have done
World Cup TrendsMap
domingo 2 de junio de 13
www.autentia.com
What others have done
Magnitude Calculator
http://hitching.net/magnitwude/
domingo 2 de junio de 13
www.autentia.com
What others have done
domingo 2 de junio de 13
www.autentia.com
The missing piece
Adding sentimental analysis
domingo 2 de junio de 13
www.autentia.com
The missing piece
Adding sentimental analysis
domingo 2 de junio de 13
www.autentia.com
The missing piece
@Value
("https://store.apicultur.com/api/stmtlk/1.0.0/valoracion/tweet/10")
private	
  String	
  serviceUrl	
  =	
  null;
private	
  RestTemplate	
  restTemplate;
<dependency>
	 <groupId>org.springframework</groupId>
	 <artifactId>spring-web</artifactId>
	 <version>${spring.version}</version>
</dependency>
domingo 2 de junio de 13
www.autentia.com
The missing piece
public	
  Sentiment	
  rate(Tweet	
  tweet)	
  {
	
  	
  	
  logger.debug("Rating	
  sentimentally	
  tweet	
  "	
  +	
  tweet.getText());
	
  	
  	
  Sentiment	
  sentiment;
	
  	
  	
  try	
  {
	
  	
  	
  	
  	
  	
  	
  sentiment	
  =	
  
restTemplate.postForObject(serviceUrl,	
  tweet,
	
  Sentiment.class);
	
  	
  	
  }	
  catch	
  (Exception	
  ex)	
  {
	
  	
  	
  	
  	
  	
  	
  logger.error("Could	
  not	
  rate	
  "	
  +	
  tweet	
  
+	
  "	
  Error:	
  "	
  +	
  ex.getMessage(),	
  ex);
	
  	
  	
  	
  	
  	
  	
  return	
  Sentiment.UNRATED;
	
  	
  	
  }
	
  	
  	
  logger.debug("Tweet	
  rated	
  sentimentally	
  as	
  :	
  "	
  +	
  sentiment);
	
  	
  	
  return	
  sentiment;
}
domingo 2 de junio de 13
www.autentia.com
The missing piece
public	
  class	
  Sentiment	
  {
	
  	
  	
  	
  private	
  static	
  final	
  int	
  LEVEL_UNKNOWN	
  =	
  0;
	
  	
  	
  	
  public	
  static	
  final	
  Sentiment	
  UNRATED	
  =	
  
new	
  Sentiment(LEVEL_UNKNOWN,	
  LEVEL_UNKNOWN,	
  "NEUTRO");
	
  	
  	
  	
  @JsonProperty("intensidad")
	
  	
  	
  	
  private	
  int	
  intensity	
  =	
  0;
	
  	
  	
  	
  @JsonProperty("certidumbre")
	
  	
  	
  	
  private	
  int	
  certainty	
  =	
  0;
	
  	
  	
  	
  @JsonProperty("ponderacion")
	
  	
  	
  	
  private	
  String	
  sentiment;
}
domingo 2 de junio de 13
www.autentia.com
The missing piece
public	
  class	
  Sentiment	
  {
	
  	
  	
  	
  private	
  static	
  final	
  int	
  LEVEL_UNKNOWN	
  =	
  0;
	
  	
  	
  	
  public	
  static	
  final	
  Sentiment	
  UNRATED	
  =	
  
new	
  Sentiment(LEVEL_UNKNOWN,	
  LEVEL_UNKNOWN,	
  "NEUTRO");
	
  	
  	
  	
  @JsonProperty("intensidad")
	
  	
  	
  	
  private	
  int	
  intensity	
  =	
  0;
	
  	
  	
  	
  @JsonProperty("certidumbre")
	
  	
  	
  	
  private	
  int	
  certainty	
  =	
  0;
	
  	
  	
  	
  @JsonProperty("ponderacion")
	
  	
  	
  	
  private	
  String	
  sentiment;
}
{
	
  	
  "intensidad":	
  4,
	
  	
  "certidumbre":	
  4,
	
  	
  "ponderacion":	
  "POSITIVA",
	
  	
  "texto":	
  "wso2	
  api	
  manager	
  interesante	
  
gestionar	
  apis	
  uso	
  http//kcyme/lqie	
  
apidays"
}
domingo 2 de junio de 13
www.autentia.com
Putting all the blocks
toghether:
GeoSentimentZ
domingo 2 de junio de 13
www.autentia.com
GeoSentimentz
domingo 2 de junio de 13
www.autentia.com
Some final considerations
Be careful with API invocation pace
(Some APIs have limits/prices)
Use Queues/Schedulers to calm API
calls traffic
Some Sentiment could not be reliable
Intruder tweets
Not spanish
Slang, arbbr, typos
domingo 2 de junio de 13
www.autentia.com
“Somos pocos, somos buenos, estamos
motivados y nos gusta lo que hacemos”
Thanks for listening
@dgomezg
@autentia
domingo 2 de junio de 13

Geo-SentimentZ

  • 1.
  • 2.
  • 3.
    www.autentia.com Want to tracksomething? Probably people is talking about it on the Web and social media domingo 2 de junio de 13
  • 4.
  • 5.
  • 6.
    www.autentia.com New ways tomeasure TPS: Tweets Per Second domingo 2 de junio de 13
  • 7.
    www.autentia.com New ways tomeasure TPS: Tweets Per Second domingo 2 de junio de 13
  • 8.
    www.autentia.com New ways tomeasure TPS: Tweets Per Second domingo 2 de junio de 13
  • 9.
    www.autentia.com New ways tomeasure TPS: Tweets Per Second domingo 2 de junio de 13
  • 10.
    www.autentia.com How influential areyou? domingo 2 de junio de 13
  • 11.
    www.autentia.com New tools tomeasure Built on APIs to get data Built on APIs to represent data domingo 2 de junio de 13
  • 12.
    www.autentia.com The Building blocks: TheAPIs domingo 2 de junio de 13
  • 13.
    www.autentia.com Google Maps API Wellknown interface Gives different layers - Map - Terrain - Satellite Place Points Of Interest Group POIs POI metadata domingo 2 de junio de 13
  • 14.
    www.autentia.com Google Maps APIuse <script  src="http://maps.google.com/maps/api/js?sensor=false"></script> var  map; function  initialize()  {    var  center  =  new  google.maps.LatLng(50,  20);    map  =  new  google.maps.Map(document.getElementById('map'),  {        zoom:  3,        center:  center,        mapTypeId:  google.maps.MapTypeId.ROADMAP    }); } google.maps.event.addDomListener(window,  'load',  initialize); domingo 2 de junio de 13
  • 15.
    www.autentia.com Google Maps APIuse <script  src="http://maps.google.com/maps/api/js?sensor=false"></script> var  map; function  initialize()  {    var  center  =  new  google.maps.LatLng(50,  20);    map  =  new  google.maps.Map(document.getElementById('map'),  {        zoom:  3,        center:  center,        mapTypeId:  google.maps.MapTypeId.ROADMAP    }); } google.maps.event.addDomListener(window,  'load',  initialize); <div id="map-container"> <div id="map"></div> </div> domingo 2 de junio de 13
  • 16.
    www.autentia.com Google Maps APIuse function  callEvents(){   var  searchQuery  =  $('#searchQuery').value;   $.ajax({     url:  '/sentimentz/pois/'  +  encodeURIComponent(searchQuery),     type:  'GET',     contentType:  'application/json',     success:  function(data){       setTimeout(function(){  putEvents(data)},  500);     },     error:  function(data,  status,  er){       //....     }   }); } domingo 2 de junio de 13
  • 17.
    www.autentia.com Google Maps APIuse function  callEvents(){   var  searchQuery  =  $('#searchQuery').value;   $.ajax({     url:  '/sentimentz/pois/'  +  encodeURIComponent(searchQuery),     type:  'GET',     contentType:  'application/json',     success:  function(data){       setTimeout(function(){  putEvents(data)},  500);     },     error:  function(data,  status,  er){       //....     }   }); } [      {            "rate":0,            "msg":"Muy  buena  exposición    sobre  API  business   model  #APIDays",            "location":{                  "latitude":40.44614387,                  "longitude":-­‐3.67365923            },            "id":340414678016593920,            "createAt":1369996158000      } ] domingo 2 de junio de 13
  • 18.
    www.autentia.com Google Maps APIuse function  putEvents(events){   var  bounds  =  new  google.maps.LatLngBounds();   var  markers  =  [];   document.getElementById("totalGeoTweets").innerHTML  =  events.length;        for  (var  i  =  0;  i  <  events.length;  i++)  {            var  event  =  events[i];            var  latLng  =  new  google.maps.LatLng(event.location.latitude,                    event.location.longitude);            bounds.extend(latLng);            var  marker  =  new  google.maps.Marker({                position:  latLng,                map:  map,            });            markers.push(marker);        }   map.fitBounds(bounds);        var  markerCluster  =  new  MarkerClusterer(map,  markers); } domingo 2 de junio de 13
  • 19.
    www.autentia.com The Source: twitter Anopen window to shout your thougths... ... that everyone can listen #hashtags @users queryStrings Geolocalized domingo 2 de junio de 13
  • 20.
    www.autentia.com Info contained ina tweet http://www.geekosystem.com/tweet-diagram/ domingo 2 de junio de 13
  • 21.
    www.autentia.com Twitter: The searchAPI domingo 2 de junio de 13
  • 22.
    www.autentia.com Twitter: The searchAPI <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>3.0.3</version> </dependency> domingo 2 de junio de 13
  • 23.
    www.autentia.com Twitter: The searchAPI <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>3.0.3</version> </dependency> public  List<Event>  retrieveAllTweetsByQuery(String  hashtag)     throws  TwitterException,  MalformedURLException  {   Twitter  twitter  =  TwitterFactory.getInstance();   Query  query  =  new  Query(hashtag);   QueryResult  result;   List<Status>  tweets  =  new  ArrayList<Status>();   do  {     result  =  twitter.search(query);     tweets.addAll(result.getTweets());   }  while  ((query  =  result.nextQuery())  !=  null); }   domingo 2 de junio de 13
  • 24.
    www.autentia.com Twitter: The searchAPI public  List<Event>  retrieveAllTweetsByQuery(String  hashtag)     throws  TwitterException,  MalformedURLException  {   Twitter  twitter  =  getTwitterAccessor();   Query  query  =  new  Query(hashtag);   QueryResult  result;   List<Status>  tweets  =  new  ArrayList<Status>();   do  {     result  =  twitter.search(query);     tweets.addAll(result.getTweets());   }  while  ((query  =  result.nextQuery())  !=  null); }   domingo 2 de junio de 13
  • 25.
    www.autentia.com What others havedone World Cup TrendsMap domingo 2 de junio de 13
  • 26.
    www.autentia.com What others havedone Magnitude Calculator http://hitching.net/magnitwude/ domingo 2 de junio de 13
  • 27.
    www.autentia.com What others havedone domingo 2 de junio de 13
  • 28.
    www.autentia.com The missing piece Addingsentimental analysis domingo 2 de junio de 13
  • 29.
    www.autentia.com The missing piece Addingsentimental analysis domingo 2 de junio de 13
  • 30.
    www.autentia.com The missing piece @Value ("https://store.apicultur.com/api/stmtlk/1.0.0/valoracion/tweet/10") private  String  serviceUrl  =  null; private  RestTemplate  restTemplate; <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> domingo 2 de junio de 13
  • 31.
    www.autentia.com The missing piece public  Sentiment  rate(Tweet  tweet)  {      logger.debug("Rating  sentimentally  tweet  "  +  tweet.getText());      Sentiment  sentiment;      try  {              sentiment  =   restTemplate.postForObject(serviceUrl,  tweet,  Sentiment.class);      }  catch  (Exception  ex)  {              logger.error("Could  not  rate  "  +  tweet   +  "  Error:  "  +  ex.getMessage(),  ex);              return  Sentiment.UNRATED;      }      logger.debug("Tweet  rated  sentimentally  as  :  "  +  sentiment);      return  sentiment; } domingo 2 de junio de 13
  • 32.
    www.autentia.com The missing piece public  class  Sentiment  {        private  static  final  int  LEVEL_UNKNOWN  =  0;        public  static  final  Sentiment  UNRATED  =   new  Sentiment(LEVEL_UNKNOWN,  LEVEL_UNKNOWN,  "NEUTRO");        @JsonProperty("intensidad")        private  int  intensity  =  0;        @JsonProperty("certidumbre")        private  int  certainty  =  0;        @JsonProperty("ponderacion")        private  String  sentiment; } domingo 2 de junio de 13
  • 33.
    www.autentia.com The missing piece public  class  Sentiment  {        private  static  final  int  LEVEL_UNKNOWN  =  0;        public  static  final  Sentiment  UNRATED  =   new  Sentiment(LEVEL_UNKNOWN,  LEVEL_UNKNOWN,  "NEUTRO");        @JsonProperty("intensidad")        private  int  intensity  =  0;        @JsonProperty("certidumbre")        private  int  certainty  =  0;        @JsonProperty("ponderacion")        private  String  sentiment; } {    "intensidad":  4,    "certidumbre":  4,    "ponderacion":  "POSITIVA",    "texto":  "wso2  api  manager  interesante   gestionar  apis  uso  http//kcyme/lqie   apidays" } domingo 2 de junio de 13
  • 34.
    www.autentia.com Putting all theblocks toghether: GeoSentimentZ domingo 2 de junio de 13
  • 35.
  • 36.
    www.autentia.com Some final considerations Becareful with API invocation pace (Some APIs have limits/prices) Use Queues/Schedulers to calm API calls traffic Some Sentiment could not be reliable Intruder tweets Not spanish Slang, arbbr, typos domingo 2 de junio de 13
  • 37.
    www.autentia.com “Somos pocos, somosbuenos, estamos motivados y nos gusta lo que hacemos” Thanks for listening @dgomezg @autentia domingo 2 de junio de 13