Разработка сервиса агрегации открытых данных и данных из социальных сетей
Анализ предметной области. Выбор источника и наборов открытых данных. Сравнение программных интерфейсов социальных сетей. Ограничение географической локации сообщений. Разработка формата хранения данных. Визуализация собранных данных методом теплой карты.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 03.07.2017 |
Размер файла | 3,5 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
На данный момент в сервисе реализованы клиенты для двух социальных сетей: Twitterи Instagram. Это одни из самых популярных на сегодняшний день платформ в мире. Они имеют развитый и технически сложный программный интерфейс, позволяющие выстраивать гибкие запросы к своим базам данных. Интеграция с другими сетями была осложнена рядом факторов, которые ранее уже были описаны в данной работе. Тем не менее, ограничение клиентов было вызвано только ограничением по времени написания сервиса. Стоит отметить, что количество клиентов под разные социальные сети является хорошей точкой роста и развития для сервиса. Дело в том, что чем больше сообщений будет обрабатывать и сервис агрегации, тем точнее должна получаться визуализация активности пользователей. В последствие можно будет добавить другие социальные сети, например, мирового лидера в лице Facebook и более успешного игрока на российском рынке - Вконтакте.
Использование современных технологий разработки оставляет возможность для расширения функционала. Есть масса идей, которые позволят качественно улучшить сервис и развить в нем свой потенциал. Каждый день или любой другой отрезок времени отслеживать, где пользователи наиболее активно себя проявляют в социальных сетях. Далее с помощью загруженных наборов открытых данных можно сопоставлять их географическое положение и определять, какой объект является самым популярным на это время. Это может послужить своего рода рекомендательной системой для отслеживания трендов посещений пользователями различных заведений, музеев или выставок.
Новизна и практическая значимость исследования.
Отличительной особенностью среди всех сервисов на основе открытых данных является тот факт, что визуализация информации является динамической. Это достигается за счет агрегации потоков данных из социальных сетей в реальном времени. Недостатком сервисов, которые основываются только лишь на открытых данных, является их редкое обновление на порталах. Как правило, такие наборы данных статические и модифицируются крайне редко. Это влечет за собой такие последствия, как проблемы с удержанием интернет аудитории у веб-ресурса. Большинство пользователей, которые заходят на подобные сайты, редко возвращаются или пользуются им повторно.
Это объясняется тем, что сервис был спроектирован таким образом, чтобы обратить внимание на какую-либо проблему или явление. После того, как люди, пришедшие на интернет портал, изучили поднятый вопрос, необходимость в нем сразу отпадает. Примером может послужить проект, участвовавший в хакатоне по открытым данным. Проект заключается в том, чтобы показать общественности и властям, что некоторые велодорожки были проложены не там, где движутся велосипедисты в реальной жизни. Такие проекты можно считать одноразовыми, поскольку они полностью статичны. После посещения такого сайта интерес к данной теме теряется, а в случае повторного посещения ресурса пользователь не обнаружит ничего нового.
Иначе дело обстоит с сервисом агрегации данных. Дело в том, что сама природа социальных сетей автоматически избавляет данный сервис от подобных недостатков. Благодаря тому, что все наполнение сетей целиком и полностью генерируется пользователями, такая экосистема сразу становится динамической. Соответственно, все сервисы, которые используют пользовательскую активность в своей работе, также становятся динамическими. Все это ведет к тому, что в каждый момент времени состояние сервиса уникально. Именно это и дает преимущество перед статическими веб ресурсами, ограниченных определенным набором открытых данных. Дело в том, что с точки зрения пользователей гораздо выше вероятность повторного посещения подобного рода сайтов, поскольку они не знают наверняка, что там увидят. Изучение активности пользователей в привязке к наборам открытых данных теперь может быть растянуто по времени. Другими словами, можно выявлять значимые тренды поведения пользователей в социальных сетях, определять связь между местами скопления пользователей и объектами города, такими как парки, скверы, места общественного питания и прочие. На момент написания работы разработанный сервис не имеет аналогов.
ЗАКЛЮЧЕНИЕ
В результате выполнения выпускной квалификационной работы был реализован сервис агрегации открытых данных и данных из социальных сетей. При этом была достигнута основная цель данной работы. Стоит отметить, что автором были решены все поставленные задачи. Данная система состоит из ряда отдельных независимых модулей, выполненных согласно микросервисной архитектуре. Это клиенты под каждую поддерживаемую социальную сеть, адаптеры для конвертации сообщений в единый универсальный формат, сервис базы данных и веб-сервер для предоставления доступа к данным пользователю. Сервис представляет собой веб-сайт, который можно использовать с помощью браузера. Разработанный программный комплекс, сочетающий в себе средства для визуализации и агрегации открытых данных и данных из социальных сетей, не имеет аналогов на момент написания данной работы.
Главной особенностью данного проекта является тот факт, что с помощью сервиса можно выявлять зависимости между географическим положением пользовательской активности, ее интенсивностью и объектами из набора открытых данных. Так, благодаря интуитивно понятной визуализации вышеперечисленных данных, можно анализировать места скопления людей, которые являются пользователями социальных сетей. С помощью данного сервиса можно выявлять закономерности в расположении объектов города, например парков и музеев, и пользовательской активностью. Благодаря ему можно понять, какие места пользуются спросом у людей, а какие являются непопулярными. Например, каким паркам, помимо ухода за территорией, стоит обратить внимание на наполнение запоминающимися объектами. К ним можно отнести арт-объекты или памятники. Все это будет вести к повышению вовлеченности посетителей, что в свою очередь приведет к их желанию поделиться своими впечатлениями со своими друзьями и знакомыми в социальных сетях. Более того, данный сервис поможет выявить такое явление как сезонность. Такая информация может быть полезна во многих сферах жизни, например, представителям рекламных агентств или сетей общественного питания.
Также следует обратить внимание, что в связи с использованием самых современных инструментов и технологий индустрии разработки программного обеспечения, разработанный сервис получился очень гибким в плане поддержки и развертывания. Дело в том, что система является независимой от платформы. Другими словами, она может выполняться на любой операционной системе, где есть виртуальная машина Java. Также в виду использования микросервисной архитектуры, отдельные независимые сервисы легко поддаются контейнеризации. Такой подход сейчас стараются поддерживать все передовые корпорации, занимающиеся разработкой программного обеспечения и облачными технологиями. Самым распространенным способом является использование технологии Docker, позволяющей без проблем производить горизонтальное масштабирование приложений и удобное администрирование систем.
Несмотря на то, что сервис представляет собой готовый к использованию программный продукт, существует несколько способов для его улучшения. В первую очередь, в систему может быть добавлена автоматическая рекомендательная система, которая способна распознавать тренды активности пользователей в социальных сетях, сопоставлять с наборами открытых данных и делать выводы о том, какие места в данный момент пользуются популярностью. Также стоит отметить, что с помощью добавления в систему новых клиентов для других социальны сетей, точность работы сервиса должна увеличиться. Это можно объяснить тем, что такая тепловая карта будет еще более показательная, а визуализация даст наиболее полную картину. Таким образом, у проекта существует потенциал для развития и роста.
СПИСОКИСПОЛЬЗУЕМЫХИСТОЧНИКОВ
1. Boyd D., Ellison N.B. Social Network sites: Definition, history and scholarship // Journal of Computer-Mediated Communication, 2011, №11.
2. Chan Y. “A Distributed Stream Library for Java 8,” Ph.D. dissertation, University of York, 2016.
3. Chowdhury M., Zaharia M., Stoica I., Performance and Scalability of Broadcast in Spark. 2010.
4. Dewire D.T. Client-server computing. McGrawHill, Singapore, 1993.
5. Digital Fuel of the 21st Century: Innovation through Open Data and the Network Effect, Harvard University, 2011.
6. Eur-Lex, Open data An engine for innovation, growth and transparent governance, 2011.
7. Grosso W. Java RMI. First Edition. O'Reilly and Associates, USA, 2001.
8. Kumar K., Liu J., Lu Y., Bhargava B., “A survey of computation offloading for mobile systems,” Mobile Networks and Applications, vol. 18, no. 1, pp. 129-140, 2013.
9. Lahiri M., Berger-Wolf T., “Mining Periodic Behavior in Dynamic Social Networks,” Proceedings of the 8th IEEE Inter-national Conference on Data Mining, 2008, pp. 373-382.
10. Ricardo T., Marco T.V., Roberto S.B. An approach for extracting modules from monolithic software architectures. Workshop, pages 1-18, 2012.
11. Scharl, A. Towards the Geospatial Web: Media Platforms for Managing Geotagged Knowledge Repositories. The Geospatial Web Geobrowsers, Social Software and the Web 2.0 are Shaping the Network Society (pp. 3-14). London: Springer, 2007.
12. Twitter Developer Documentation [Электронныйресурс] // URL: https://dev.twitter.com/overview/api/tweets (Датаобращения 18.04.2017).
13. Venner J., Pro Hadoop. Apress, June 22, 2009.
14. Wang G., Xiong Y., Yun J., Cavallaro J. “Accelerating computer vision algorithms using OpenCL framework on the mobile GPU--a case study,” in Proceedings of the 38th IEEE International Conference on Acoustics, Speech, and Signal Processing (ICASSP '13), IEEE, Vancouver, Canada, May 2013.
15. Бегтин И.В. Проблема открытых данных в России // Земля из космоса. 2011. №11. С.20-25.
16. Борисенко О.Д., Турдаков Д. Ю., Кузнецов С. Д., Автоматическое создание виртуальных кластеров ApacheSpark в облачной среде OpenStack. Труды Института системного программирования РАН, том 17, 2009 г. Стр 31-50.
17. Катков Е.В., Сорочайкин А.Н. Моедирование процессов инновационного развития предприятий // Вестник Самарского государственного университета. 2012. №10. С.33-39.
18. Остервальдер А., Пинье И. Построение бизнес-моделей. Настольная книга стратега и новатора. -- М.: Альпина Паблишер, 2011.
ПРИЛОЖЕНИЕ
ТЕКСТ ПРОГРАММЫ
MapController.java
packagecom.alexcodes.web.controller;
importcom.alexcodes.web.dto.MapDTO;
importcom.alexcodes.web.service.MapService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.http.MediaType;
importorg.springframework.util.Assert;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/map")
public class MapController {
private final MapServicemapService;
@Autowired
publicMapController(MapServicemapService) {
Assert.notNull(mapService, "Cannot be null");
this.mapService = mapService;
}
@RequestMapping(value = "/coordinates",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
publicMapDTOgetCoordinates() {
returnmapService.getMap();
}
}
CoordinatesService.java
packagecom.alexcodes.web.service;
importjava.util.List;
public interface CoordinatesService {
List<List<Double>>findCoordinates();
}
MapService.java
packagecom.alexcodes.web.service;
importcom.alexcodes.web.dto.MapDTO;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importorg.springframework.util.Assert;
@Service
public class MapService {
private final CoordinatesServicecoordinatesService;
@Autowired
publicMapService(CoordinatesServicecoordinatesService) {
Assert.notNull(coordinatesService, "Cannot be null");
this.coordinatesService = coordinatesService;
}
publicMapDTOgetMap() {
MapDTOdto = new MapDTO();
dto.coordinates = coordinatesService.findCoordinates();
returndto;
}
}
SimpleCoordinatesService.java
packagecom.alexcodes.web.service;
importcom.alexcodes.common.dao.GeoPostRepository;
importcom.alexcodes.common.domain.GeoPost;
importcom.google.common.collect.Lists;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Profile;
importorg.springframework.stereotype.Service;
importjava.util.Arrays;
importjava.util.List;
importjava.util.Objects;
importjava.util.stream.Collectors;
@Service
@Profile("default")
public class SimpleCoordinatesService implements CoordinatesService {
private final GeoPostRepositorygeoPostRepository;
@Autowired
publicSimpleCoordinatesService(GeoPostRepositorygeoPostRepository) {
this.geoPostRepository = geoPostRepository;
}
@Override
public List<List<Double>>findCoordinates() {
List<GeoPost> posts = Lists.newArrayList(geoPostRepository.findAll());
returnposts.stream()
.map(post ->post.location)
.filter(Objects::nonNull)
.filter(location ->location.latitude != 55.7547875 &&location.longitude != 37.427642500000005)
.map(location ->Arrays.asList(location.latitude, location.longitude))
.collect(Collectors.toList());
}
}
CoordinateDTO.java
packagecom.alexcodes.web.dto;
public class CoordinateDTO {
public double longitude;
public double latitude;
publicCoordinateDTO() {
}
publicCoordinateDTO(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
}
MapDTO.java
packagecom.alexcodes.web.dto;
importjava.time.Instant;
importjava.util.List;
public class MapDTO {
public Instant lastModified;
public List<List<Double>> coordinates;
}
WebMain.java
packagecom.alexcodes.web;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.alexcodes.*")
public class WebMain {
public static void main(String[] args) {
SpringApplication.run(WebMain.class);
}
}
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Social Parks</title>
<link href="https://yandex.st/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
html, body, .hero-unit {
min-height: 100%;
height: 100%;
margin: 0;
}
#YMapsID {
width: 900px;
height: 700px;
}
#YMapsCode {
width: 880px;
}
</style>
<script src="js/jquery-3.2.1.min.js" type="text/javascript"></script>
<script src="http://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script src="js/heatmap.min.js" type="text/javascript"></script>
<script type="text/javascript">
ymaps.ready(function () {
$.get("/map/coordinates", function (response) {
var data = response.coordinates;
var map = new ymaps.Map('YMapsID', {
center: [55.751588, 37.617861],
controls: ['zoomControl', 'typeSelector', 'fullscreenControl'],
zoom: 11, type: 'yandex#satellite'
}),
buttons = {
dissipating: new ymaps.control.Button({
data: {
content: 'Toggle dissipating'
},
options: {
selectOnClick: false,
maxWidth: 150
}
}),
opacity: new ymaps.control.Button({
data: {
content: 'Change opacity'
},
options: {
selectOnClick: false,
maxWidth: 150
}
}),
radius: new ymaps.control.Button({
data: {
content: 'Change radius'
},
options: {
selectOnClick: false,
maxWidth: 150
}
}),
gradient: new ymaps.control.Button({
data: {
content: 'Reverse gradient'
},
options: {
selectOnClick: false,
maxWidth: 150
}
}),
heatmap: new ymaps.control.Button({
data: {
content: 'Toggle Heatmap'
},
options: {
selectOnClick: false,
maxWidth: 150
}
})
},
gradients = [{
0.1: 'rgba(128, 255, 0, 0.7)',
0.2: 'rgba(255, 255, 0, 0.8)',
0.7: 'rgba(234, 72, 58, 0.9)',
1.0: 'rgba(162, 36, 25, 1)'
}, {
0.1: 'rgba(162, 36, 25, 0.7)',
0.2: 'rgba(234, 72, 58, 0.8)',
0.7: 'rgba(255, 255, 0, 0.9)',
1.0: 'rgba(128, 255, 0, 1)'
}],
radiuses = [5, 10, 20, 30],
opacities = [0.4, 0.6, 0.8, 1];
ymaps.modules.require(['Heatmap'], function (Heatmap) {
varheatmap = new Heatmap(data, {
gradient: gradients[0],
radius: radiuses[1],
opacity: opacities[2]
});
heatmap.setMap(map);
buttons.dissipating.events.add('press', function () {
heatmap.options.set(
'dissipating', !heatmap.options.get('dissipating')
);
});
buttons.opacity.events.add('press', function () {
var current = heatmap.options.get('opacity'),
index = opacities.indexOf(current);
heatmap.options.set(
'opacity', opacities[++index == opacities.length ? 0 : index]
);
});
buttons.radius.events.add('press', function () {
var current = heatmap.options.get('radius'),
index = radiuses.indexOf(current);
heatmap.options.set(
'radius', radiuses[++index == radiuses.length ? 0 : index]
);
});
buttons.gradient.events.add('press', function () {
var current = heatmap.options.get('gradient');
heatmap.options.set(
'gradient', current == gradients[0] ? gradients[1] : gradients[0]
);
});
buttons.heatmap.events.add('press', function () {
heatmap.setMap(
heatmap.getMap() ? null : map
);
});
for (var key in buttons) {
if (buttons.hasOwnProperty(key)) {
map.controls.add(buttons[key]);
}
}
});
});
});
</script>
</head>
<body>
<div class="hero-unit">
<div class="container">
<p>Yandex Maps API <a href="https://github.com/yandex/mapsapi-heatmap">Heatmap Module</a></p>
<div id="YMapsID"></div>
</div>
</div>
</body>
</html>
MongoConfiguration.java
packagecom.alexcodes.common.config;
importcom.mongodb.Mongo;
importcom.mongodb.MongoClient;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@Configuration
@EnableMongoRepositories({"com.alexcodes.common.dao"})
public class MongoConfiguration extends AbstractMongoConfiguration {
@Value("${spring.data.mongodb.host}")
private String host;
@Value("${spring.data.mongodb.port}")
privateint port;
@Value("${spring.data.mongodb.database}")
private String database;
@Override
protected String getDatabaseName() {
return database;
}
@Override
public Mongo mongo() throws Exception {
return new MongoClient(host, port);
}
}
GeoPost.java
packagecom.alexcodes.common.domain;
importcom.google.common.base.MoreObjects;
importorg.springframework.data.annotation.Id;
importjava.time.Instant;
public class GeoPost {
@Id
public String id;
publicSourceTypesourceType;
public String text;
public Location location;
public Instant timestamp;
@Override
public String toString() {
returnMoreObjects.toStringHelper(this)
.add("sourceType", sourceType)
.add("text", text)
.add("location", location)
.add("timestamp", timestamp)
.toString();
}
}
Location.java
packagecom.alexcodes.common.domain;
importcom.google.common.base.MoreObjects;
public class Location {
public Type type;
public double longitude;
public double latitude;
public Location() {}
public Location(Type type, double longitude, double latitude) {
this.type = type;
this.longitude = longitude;
this.latitude = latitude;
}
@Override
public String toString() {
returnMoreObjects.toStringHelper(this)
.add("longitude", longitude)
.add("latitude", latitude)
.toString();
}
publicenum Type {
POINT, CITY
}
}
AppConfig.java
packagecom.alexcodes.twitter.config;
importcom.twitter.hbc.core.endpoint.Location;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
@Configuration
public class TwitterConfig {
@Value("${twitter.location.southwest.longitude}")
private double southWestLongitude;
@Value("${twitter.location.southwest.latitude}")
private double southWestLatitude;
@Value("${twitter.location.northeast.longitude}")
private double northEastLongitude;
@Value("${twitter.location.northeast.latitude}")
private double northEastLatitude;
@Bean
public Location location() {
return new Location(
newLocation.Coordinate(southWestLongitude, southWestLatitude),
newLocation.Coordinate(northEastLongitude, northEastLatitude));
}
}
LocationExtractor.java
packagecom.alexcodes.twitter.logic;
importcom.alexcodes.common.domain.Location;
importcom.google.gson.JsonArray;
importcom.google.gson.JsonElement;
importcom.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
importorg.springframework.stereotype.Service;
importjava.util.ArrayList;
importjava.util.List;
@Service
public class LocationExtractor {
private static final Logger log = LoggerFactory.getLogger(LocationExtractor.class);
private static final String COORDINATES = "coordinates";
private static final String PLACE = "place";
private static final String PLACE_TYPE = "place_type";
private static final String CITY = "city";
private static final String BOUNDING_BOX = "bounding_box";
private static final String TYPE = "type";
private static final String POLYGON = "Polygon";
public Location getLocation(JsonObject root) {
JsonElement coordinates = root.get(COORDINATES);
if (coordinates != null && !coordinates.isJsonNull())
returnextractCoordinates(coordinates);
JsonElement place = root.get(PLACE);
if (place != null && !place.isJsonNull())
returnextractPlace(place);
log.error("Cannot extract location from {}", root);
return null;
}
private Location extractCoordinates(JsonElement coordinates) {
JsonArray array = coordinates.getAsJsonObject().getAsJsonArray(COORDINATES);
double longitude = array.get(0).getAsDouble();
double latitude = array.get(1).getAsDouble();
return new Location(Location.Type.POINT, longitude, latitude);
}
private Location extractPlace(JsonElement place) {
String placeType = place.getAsJsonObject().get(PLACE_TYPE).getAsString();
JsonObjectboundingBox = place.getAsJsonObject().getAsJsonObject(BOUNDING_BOX);
if (!placeType.equals(CITY)) {
log.warn("Unknown placeType: {}", placeType);
return null;
}
Point point = extractBoundingBox(boundingBox);
return new Location(Location.Type.CITY, point.longitude, point.latitude);
}
private Point extractBoundingBox(JsonObjectboundingBox) {
String type = boundingBox.getAsJsonPrimitive(TYPE).getAsString();
switch (type) {
case POLYGON: {
JsonArray coordinates = boundingBox.getAsJsonArray(COORDINATES)
.get(0)
.getAsJsonArray();
List<Double> longs = new ArrayList<>(coordinates.size());
List<Double>lats = new ArrayList<>(coordinates.size());
for (inti = 0; i<coordinates.size(); i++) {
JsonArray point = coordinates.get(i).getAsJsonArray();
longs.add(point.get(0).getAsDouble());
lats.add(point.get(1).getAsDouble());
}
doubleavgLong = longs.stream()
.mapToDouble(Double::doubleValue)
.average()
.getAsDouble();
doubleavgLat = lats.stream()
.mapToDouble(Double::doubleValue)
.average()
.getAsDouble();
return new Point(avgLong, avgLat);
}
default:
log.error("Unknown format: {}", boundingBox);
return new Point(0.0, 0.0);
}
}
private static class Point {
public double longitude;
public double latitude;
public Point(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
}
}
PostConverter.java
packagecom.alexcodes.twitter.logic;
importcom.alexcodes.common.domain.GeoPost;
importcom.alexcodes.common.domain.SourceType;
importcom.alexcodes.common.logic.PostConverter;
importcom.google.gson.JsonElement;
importcom.google.gson.JsonObject;
importcom.google.gson.JsonParser;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importjava.time.Instant;
importjava.time.format.DateTimeFormatter;
@Service
public class TweetConverter implements PostConverter {
private static final String TEXT = "text";
private static final String CREATED_AT = "created_at";
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("E MMM ddHH:mm:ss Z yyyy");
private final LocationExtractorlocationExtractor;
@Autowired
publicTweetConverter(LocationExtractorlocationExtractor) {
this.locationExtractor = locationExtractor;
}
@Override
publicGeoPost convert(String message) {
JsonParser parser = new JsonParser();
JsonObject root = parser.parse(message).getAsJsonObject();
GeoPost post = new GeoPost();
post.sourceType = SourceType.TWITTER;
post.text = getText(root);
post.location = locationExtractor.getLocation(root);
post.timestamp = getTimestamp(root);
return post;
}
private String getText(JsonObject root) {
returnroot.getAsJsonPrimitive(TEXT).getAsString();
}
private Instant getTimestamp(JsonObject root) {
JsonElementcreatedAt = root.get(CREATED_AT);
if (createdAt == null) return null;
String timestamp = createdAt.getAsString();
returnformatter.parse(timestamp).query(Instant::from);
}
}
PostProcessor.java
packagecom.alexcodes.twitter.logic;
importcom.alexcodes.common.dao.GeoPostRepository;
importcom.alexcodes.common.domain.GeoPost;
importcom.alexcodes.common.logic.PostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
@Service
public class TweetProcessor implements PostProcessor {
private static final Logger log = LoggerFactory.getLogger(TweetProcessor.class);
private final TweetConvertertweetConverter;
private final GeoPostRepositorygeoPostRepository;
@Autowired
publicTweetProcessor(
TweetConvertertweetConverter,
GeoPostRepositorygeoPostRepository) {
this.tweetConverter = tweetConverter;
this.geoPostRepository = geoPostRepository;
}
@Override
public void process(String message) {
try {
GeoPost post = tweetConverter.convert(message);
log.debug("Tweet: {}", post);
geoPostRepository.save(post);
} catch (RuntimeException e) {
log.error("Exception during tweet processing:", e);
}
}
}
Listener.java
packagecom.alexcodes.twitter.service;
importcom.alexcodes.twitter.logic.TweetProcessor;
importcom.twitter.hbc.ClientBuilder;
importcom.twitter.hbc.core.Client;
importcom.twitter.hbc.core.Constants;
importcom.twitter.hbc.core.Hosts;
importcom.twitter.hbc.core.HttpHosts;
importcom.twitter.hbc.core.endpoint.Location;
importcom.twitter.hbc.core.endpoint.StatusesFilterEndpoint;
importcom.twitter.hbc.core.event.Event;
importcom.twitter.hbc.core.processor.StringDelimitedProcessor;
importcom.twitter.hbc.httpclient.auth.Authentication;
import com.twitter.hbc.httpclient.auth.OAuth1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.boot.CommandLineRunner;
importorg.springframework.stereotype.Service;
importorg.springframework.util.Assert;
importjava.util.Collections;
importjava.util.List;
importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.LinkedBlockingQueue;
@Service
public class TwitterListener implements CommandLineRunner {
private static final Logger log = LoggerFactory.getLogger(TwitterListener.class);
private static final int QUEUE_SIZE = 1000;
@Value("${twitter.consumerKey}")
private String consumerKey;
@Value("${twitter.consumerSecret}")
private String consumerSecret;
@Value("${twitter.token}")
private String token;
@Value("${twitter.tokenSecret}")
private String tokenSecret;
@Value("${twitter.client.name}")
private String clientName;
private final Location location;
private final TweetProcessortweetProcessor;
@Autowired
publicTwitterListener(Location location, TweetProcessortweetProcessor) {
Assert.notNull(location, "Location cannot be null");
Assert.notNull(tweetProcessor, "Cannot be null");
this.location = location;
this.tweetProcessor = tweetProcessor;
}
public void run(String... strings) throws Exception {
// Set up your blocking queues: Be sure to size these properly based on expected TPS of your stream
BlockingQueue<String>msgQueue = new LinkedBlockingQueue<>(QUEUE_SIZE);
BlockingQueue<Event>eventQueue = new LinkedBlockingQueue<>(QUEUE_SIZE);
// Declare the host you want to connect to, the endpoint, and authentication (basic auth or oauth)
Hosts hosebirdHosts = new HttpHosts(Constants.STREAM_HOST);
StatusesFilterEndpointhosebirdEndpoint = new StatusesFilterEndpoint();
// Optional: set up some followings and track terms
List<Location> locations = Collections.singletonList(location);
hosebirdEndpoint.locations(locations);
// These secrets should be read from a config file
Authentication hosebirdAuth = new OAuth1(consumerKey, consumerSecret, token, tokenSecret);
ClientBuilder builder = new ClientBuilder()
.name(clientName)
.hosts(hosebirdHosts)
.authentication(hosebirdAuth)
.endpoint(hosebirdEndpoint)
.processor(new StringDelimitedProcessor(msgQueue))
.eventMessageQueue(eventQueue);
Client hosebirdClient = builder.build();
hosebirdClient.connect();
inti = 0;
long time = System.currentTimeMillis();
// on a different thread, or multiple different threads....
while (!hosebirdClient.isDone()) {
String message = msgQueue.take();
// log.debug("Receive: {}", message);
tweetProcessor.process(message);
i++;
// if (System.currentTimeMillis() - time > 60_000L) break;
}
log.info("{} TPS", i);
hosebirdClient.stop();
}
}
Размещено на Allbest.ur
...Подобные документы
Обзор существующих решений на основе открытых данных. Выбор социальных сетей для извлечения данных. Ограничение геолокации сообщений из социальных сетей. Разработка формата хранения. Визуализация собранных данных методом теплой карты. Архитектура системы.
дипломная работа [1,0 M], добавлен 18.11.2017Обзор существующих решений на основе открытых данных. Технологии обработки данных и методы их визуализации. Социальные сети для извлечения данных. Ограничение географической локации. Выбор набора и формат хранения открытых данных, архитектура системы.
курсовая работа [129,5 K], добавлен 09.06.2017Обзор рынка мобильных приложений, социальных сетей, аналогов. Обзор инструментов разработки: Android Studio, Microsoft visual С# 2012, PostgreeSQL, API Открытых данных Вологодской области, API Социальных сетей. Программный код, разработка интерфейса.
дипломная работа [2,6 M], добавлен 10.07.2017Разработка приложения для осуществления работы с медицинскими данными с последующей их визуализацией. Изучение типов данных и свойств полей Access. Компоненты наборов данных. Структура базы данных для клиники. Экранные формы для отображения справочников.
курсовая работа [1,5 M], добавлен 14.08.2014Разработка базы данных для предметной области "Подразделения предприятия – Рабочие помещения". Описание используемых данных, предметной области и результатной информации. Создание запросов, форм и отчетов в базе данных. Описание построения диаграмм.
курсовая работа [5,6 M], добавлен 24.07.2014Проектирование логической структуры базы данных методом нормальных форм, сущность связь. Сравнительный анализ спроектированной базы данных и базы данных существующих информационных систем. Выбор и обоснование состава технических и программных средств.
курсовая работа [3,0 M], добавлен 22.12.2014Разработка информационной системы для хранения данных для предметной области "Самолеты аэропорта". Формат хранения исходных данных, их загрузка в табличный процессор. Тестирование программного комплекса. Возможности пакета MS Excel по обработке данных.
курсовая работа [1,2 M], добавлен 23.04.2014Базы данных - важнейшая составная часть информационных систем. Проектирование базы данных на примере предметной области "Оргтехника". Сбор информации о предметной области. Построение информационно-логической модели данных. Разработка логической структуры.
курсовая работа [318,6 K], добавлен 24.12.2014Проведение системного анализа предметной области и разработка проекта по созданию базы данных для хранения информации о перевозках пассажиров и грузов. Обоснование выбора системы управления базой данных и разработка прикладного программного обеспечения.
курсовая работа [1,1 M], добавлен 18.07.2014Анализ методов и средств выявления мнений пользователей социальных сетей. Обзор средств мониторинга и анализа, подбор необходимого программного обеспечения и технических средств. Разработка архитектуры базы данных, реализация программных модулей.
дипломная работа [3,7 M], добавлен 19.01.2017Концепции хранилищ данных для анализа и их составляющие: интеграции и согласования данных из различных источников, разделения наборов данных для систем обработки транзакций и поддержки принятия решений. Архитектура баз для хранилищ и витрины данных.
реферат [1,3 M], добавлен 25.03.2013Цель инфологического моделирования предметной области. Источники данных, базы данных и система управления, разработка модели. Принципы проектирования базы данных, концептуальная, логическая, материальная разработка. Типы сущностей, атрибутов и связей.
курсовая работа [188,6 K], добавлен 15.07.2012Определение базы данных и банков данных. Компоненты банка данных. Основные требования к технологии интегрированного хранения и обработки данных. Система управления и модели организации доступа к базам данных. Разработка приложений и администрирование.
презентация [17,1 K], добавлен 19.08.2013Основы работ с базами данных. Некоторые сведения о типах данных. Интерфейс БД. Текстовые, сетевые, реляционные базы данных. Проектирование баз данных. Анализ предметной области и запросов к БД. Выбор языка манипулирования данными.
курсовая работа [43,4 K], добавлен 06.10.2006Разработка базы данных с информацией о сотрудниках, товарах, со справочником типов товаров средствами системы управления базами данных MySQL с помощью SQL-запросов. Разработка инфологической модели предметной области. Структура таблиц, полей базы данных.
контрольная работа [648,7 K], добавлен 13.04.2012Понятие баз данных и принципы проектирования информационных систем. Разработка программы для отслеживания финансовой стороны работы компании в среде Delphi 7. Создание таблиц и схемы данных. Разработка клиентского приложения и процедуры добавления данных.
курсовая работа [1,4 M], добавлен 25.04.2012Сущность разработки и построения хранилища данных в цепочке локальных сетей. Его типичная структура. Особенности организации хранения информации. Алгоритм действия системы ROLAP и его сравнение с алгоритмом многомерных систем управления базами данных.
курсовая работа [743,1 K], добавлен 23.01.2015Разновидности систем управления базами данных. Анализ предметной области. Разработка структуры и ведение базы данных. Структурированный язык запросов SQL. Организация выбора информации из базы данных. Общие принципы проектирования экранных форм, макросов.
курсовая работа [3,1 M], добавлен 26.02.2016Открытые данные - машиночитаемые данные доступные для широкого круга лиц. Государство - один из самых больших потенциальных генераторов данных в сеть. Некоммерческие международные и российские негосударственные проекты, посвящённые открытым данным.
реферат [667,0 K], добавлен 25.12.2012Анализ предметной области. Предположительный набор необходимых функций. Даталогическое и инфологическое проектирование. Реляционная модель данных. Создание запросов и атрибутов. Физическая модель данных. Разработка приложения для работы с базой данных.
курсовая работа [720,8 K], добавлен 26.04.2015