logo

30 нояб. 2010 г.

BIEE 11g: Mapviewer + OpenStreetMap

Хочу поделиться опытом использования новой возможности по аналитике в привязке к картам в OBIEE 11g.

Предположим, что у вас есть задача анализировать с помощью карты ряд показателей в разрезе административных районов Санкт-Петербурга.

Что вам потребуется из инструментов:

OBIEE 11g
Mapbuilder 11
Набор shape-файлов с геоданными
БД Oracle 11.2

Подготовительная работа
1. Устанавливаем Oracle BIEE 11g
2. Скачиваем mapbuilder

Так как далее мы будем загружать геоданные в кириллице – создайте командный скрипт запуска mapbuilder – mapbuilder.cmd – и поместите его рядом со скачанным jar-файлом:
java -Dfile.encoding=UTF8 -XX:MaxPermSize=512m -Xmx1024m -jar mapbuilder.jar

3. Сами геоданные – административные районы СПб – возьмем из opensource-источника OpenStreetMap

Выкачиваем набор shp-файлов по интересующему нас региону – в моем случае – Санкт-Петербургу.

Загрузка геоданных в БД Oracle

1. Создадим в БД нового пользователя OBIEE_MAPS

CREATE USER OBIEE_MAPS IDENTIFIED BY OBIEE_MAPS DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS;

GRANT CONNECT TO OBIEE_MAPS;
GRANT RESOURCE TO OBIEE_MAPS;


2. Откроем mapbuilder. Создадим в нем новое подключение к БД под созданным пользователем.


3. Импортируем в БД данные из shape-файла. (Имя создаваемой таблице следует давать без дефисов - STPETER_ADMIN_A)




Систему координат оставьте равной 8307 – именно в ней содержатся данные OpenStreetMap.


После импорта можно их посмотреть в mapbuilder.


4. Преобразуем импортированные данные в сферическую систему координат. (Спасибо Александру Рындину за наводку – без использования опции USE_SPHERICAL «не взлетало», геоданные расходились с картой-подложкой)
create table STPETER_ADMIN_A_3785 as select * from STPETER_ADMIN_A;

update STPETER_ADMIN_A_3785 set geometry = sdo_cs.transform(geometry,'USE_SPHERICAL', 3785);

commit;

delete from user_sdo_geom_metadata where table_name = 'STPETER_ADMIN_A_3785';

insert into user_sdo_geom_metadata
values('STPETER_ADMIN_A_3785', 'GEOMETRY', sdo_dim_array(sdo_dim_element('X', -20037508.3427, 20037508.3427, 0.05), sdo_dim_element('Y', -20037508.3427, 20037508.3427, 0.05)), 3785);

-- create spatial indexes
create index STPETER_ADMIN_A_3785_sidx on STPETER_ADMIN_A_3785(GEOMETRY) indextype is mdsys.spatial_index;


5. Теперь в предпросмотре mapbuilder видим более привычную (по google/yandex maps) картину.


6. Удалим из таблицы лишние данные, чтобы остались только административные районы.
delete from stpeter_admin_a_3785 t
where nvl(t.admin_leve, -999) != 5
or t.name is null


Настроим mapviewer в поставке OBIEE 11g

Теперь необходимо настроить mapviewer – средство отображения геоданных на карте.
Так как mapviewer не работает напрямую с таблицами геоданных, потребуется еще ряд манипуляций в mapbuilder.
1. Создадим геометрическую тему.



Тема будет выглядеть так:


2. Создадим базовую карту


3. Создадим тайл

На данном этапе не будем настраивать уровни зуммирования и границы карты. Оставим так, как сгенерирует mapbuilder.




4. Зайдем в mapviewer - http://host:9704/mapviewer под администратором (weblogic)
5. Создадим постоянное подключение к нашей схеме OBIEE_MAPS




6. После перезагрузки мы видим созданное подключение и его карты.




7. Теперь создадим корректные значения границ карты и ее уровней детализации.

Откроем на редактирование строку user_sdo_cached_maps с созданным нами через mapbuilder тайлом.



Выгрузим XML с данными из столбца DEFINITION.
Заменим в нем соответствующие узлы:

<coordinate_system srid="3785" minX="-2.0037508E7" minY="-2.0037508E7" maxX="2.0037508E7" maxY="2.0037508E7"/>


И

<zoom_levels levels="20" min_scale="0.0" max_scale="0.0" min_tile_width="76.43702697753906" min_tile_height="4.00750166855785E7">
<zoom_level level="0" name="" description="" scale="0.0" tile_width="4.00750166855785E7" tile_height="4.00750166855785E7"/>
<zoom_level level="1" name="" description="" scale="0.0" tile_width="2.0037508E7" tile_height="2.0037508E7"/>
<zoom_level level="2" name="" description="" scale="0.0" tile_width="1.0018754E7" tile_height="1.0018754E7"/>
<zoom_level level="3" name="" description="" scale="0.0" tile_width="5009377.0" tile_height="5009377.0"/>
<zoom_level level="4" name="" description="" scale="0.0" tile_width="2504688.5" tile_height="2504688.5"/>
<zoom_level level="5" name="" description="" scale="0.0" tile_width="1252344.25" tile_height="1252344.25"/>
<zoom_level level="6" name="" description="" scale="0.0" tile_width="626172.125" tile_height="626172.125"/>
<zoom_level level="7" name="" description="" scale="0.0" tile_width="313086.0625" tile_height="313086.0625"/>
<zoom_level level="8" name="" description="" scale="0.0" tile_width="156543.03125" tile_height="156543.03125"/>
<zoom_level level="9" name="" description="" scale="0.0" tile_width="78271.515625" tile_height="78271.515625"/>
<zoom_level level="10" name="" description="" scale="0.0" tile_width="39135.7578125" tile_height="39135.7578125"/>
<zoom_level level="11" name="" description="" scale="0.0" tile_width="19567.87890625" tile_height="19567.87890625"/>
<zoom_level level="12" name="" description="" scale="0.0" tile_width="9783.939453125" tile_height="9783.939453125"/>
<zoom_level level="13" name="" description="" scale="0.0" tile_width="4891.9697265625" tile_height="4891.9697265625"/>
<zoom_level level="14" name="" description="" scale="0.0" tile_width="2445.98486328125" tile_height="2445.98486328125"/>
<zoom_level level="15" name="" description="" scale="0.0" tile_width="1222.992431640625" tile_height="1222.992431640625"/>
<zoom_level level="16" name="" description="" scale="0.0" tile_width="611.4962158203125" tile_height="611.4962158203125"/>
<zoom_level level="17" name="" description="" scale="0.0" tile_width="305.74810791015625" tile_height="305.74810791015625"/>
<zoom_level level="18" name="" description="" scale="0.0" tile_width="152.87405395507812" tile_height="152.87405395507812"/>
<zoom_level level="19" name="" description="" scale="0.0" tile_width="76.43702697753906" tile_height="76.43702697753906"/>
</zoom_levels>


Зачем все это – станет ясно позднее.

Затем загрузите в поле DEFINITION обновленный XML, сохраните изменения, в интерфейсе mapviewer обновите данные соединения OBIEE_MAPS.
Убедитесь, что теперь наш tile layer содержит уже 20 уровней детализации.


Настроим OBIEE для визуализации карт

Сразу оговорюсь, что в текущем релизе OBIEE есть небольшой баг, который не позволяет отобразить карты, если вы заходите в систему под русской локалью (или еще под некоторыми).
Проблема в том, что ряд javascript переменных, используемых для инициализации и отрисовки карт, может быть дробными числами.
И почему-то разделитель целой и дробной части в значениях этих переменных зависит от настроек локали.
А javascript не воспринимает число числом, если у него разделитель отличен от точки.

Лечится это просто – в файле
…Middleware/Oracle_BI1/bifoundation/web/display/localedefinitions.xml

Следует для используемой локали (“ru-ru”) установить свойство decimalSeparator равным точке.

1. Войдем в OBIEE под администратором.

Настроим слои и карты








2. Создадим в репозитории OBIEE простейшую модель для теста: таблицу измерений с ключом по имени района и таблицу фактов с одним показателем – например, суммарная задолженность абонентов района, показатель заполним случайными числами.
create table D_SPB_ADM_REGIONS as
select distinct t.name from stpeter_admin_a_3785 t

create table F_DEBT as
select t.name, abs(dbms_random.random) as debt from D_SPB_ADM_REGIONS t


3. «Протянем» эти таблицы в репозитории OBIEE.


4. Вернемся к настроенным слоям и картам в BI.

Добавим привязку слоя к ключу таблицы D_SPB_ADM_REGIONS


Переименуем слой


Повторно зайдем в карту (нужно, чтобы подцепилась связь с SubjectArea через слой карты), переименуем ее.


5. Теперь можно создать простенький ансвер, содержащий отображение данных в табличном виде, а также на карте.



Отображение подложки OpenStreetMap

Согласитесь, мы избалованы картографическими сервисами, и не видеть какую-то подложку под карту нам непривычно.

Далее описывается как настроить OBIEE для автоматического отображения вместе с любой картой ансверов подложки от OpenStreetMap (напоминаю, что это opensource источник).


1. Найдите файл

…Middleware/Oracle_BI1/bifoundation/web/app/res/b_mozilla/views/map/obips.map.js

Файл этот «оптимизирован» для веб – удалены все лишние пробелы, символы перевода строки – читать его сложно. Как вариант, воспользуйтесь утилитой Polystyle.


Нас интересует в нем функция
obips.Map.Viewer.prototype.initTileLayer

в нее следует добавить изменения:

//jack carver start

var osmMapConfig=
{
"mapTileLayer":"OSM_MERCATOR",
"format":"PNG",
"coordSys":
{
"srid":3785,
"type":"PROJECTED",
"distConvFactor":1.0,
"minX":-2.0037508E7,"minY":-2.0037508E7,
"maxX":2.0037508E7,"maxY":2.0037508E7
},
"zoomLevels":
[
{"zoomLevel":0,"name":"","tileWidth":4.00750166855785E7,"tileHeight":4.00750166855785E7,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":1,"name":"","tileWidth":2.0037508E7,"tileHeight":2.0037508E7,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":2,"name":"","tileWidth":1.0018754E7,"tileHeight":1.0018754E7,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":3,"name":"","tileWidth":5009377.0,"tileHeight":5009377.0,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":4,"name":"","tileWidth":2504688.5,"tileHeight":2504688.5,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":5,"name":"","tileWidth":1252344.25,"tileHeight":1252344.25,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":6,"name":"","tileWidth":626172.125,"tileHeight":626172.125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":7,"name":"","tileWidth":313086.0625,"tileHeight":313086.0625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":8,"name":"","tileWidth":156543.03125,"tileHeight":156543.03125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":9,"name":"","tileWidth":78271.515625,"tileHeight":78271.515625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":10,"name":"","tileWidth":39135.7578125,"tileHeight":39135.7578125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":11,"name":"","tileWidth":19567.87890625,"tileHeight":19567.87890625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":12,"name":"","tileWidth":9783.939453125,"tileHeight":9783.939453125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":13,"name":"","tileWidth":4891.9697265625,"tileHeight":4891.9697265625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":14,"name":"","tileWidth":2445.98486328125,"tileHeight":2445.98486328125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":15,"name":"","tileWidth":1222.992431640625,"tileHeight":1222.992431640625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":16,"name":"","tileWidth":611.4962158203125,"tileHeight":611.4962158203125,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":17,"name":"","tileWidth":305.74810791015625,"tileHeight":305.74810791015625,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":18,"name":"","tileWidth":152.87405395507812,"tileHeight":152.87405395507812,"tileImageWidth":256,"tileImageHeight":256},
{"zoomLevel":19,"name":"","tileWidth":76.43702697753906,"tileHeight":76.43702697753906,"tileImageWidth":256,"tileImageHeight":256}
]
};


function getOSMMapTileURL(tx, ty, tw, th, level)
{
var x = (tx-osmMapConfig.coordSys.minX)/osmMapConfig.zoomLevels[level].tileWidth ;
var y = (osmMapConfig.coordSys.maxY-ty)/osmMapConfig.zoomLevels[level].tileHeight-1 ;
// use mapnik rendered tiles
return "http://tile.openstreetmap.org/"+(level)+"/"+x+"/"+y+".png";
// use osmarender instead
//return "http://tah.openstreetmap.org/Tiles/tile/"+(level)+"/"+x+"/"+y+".png";
}
//jack carver end


obips.Map.Viewer.prototype.initTileLayer = function()
{
this.maptile = new MVMapTileLayer(this.model.getMapContext().getTileName());
this.mapview.addMapTileLayer(this.maptile, obips.Map.createCallBack(this, this.continueLoad))

//jack carver start

var osmBasemap = new MVCustomMapTileLayer(osmMapConfig, getOSMMapTileURL);
this.mapview.addMapTileLayer(osmBasemap);

window.myMapView = this.mapview; //for future purpose – jack carver
//jack carver end

};


Измененный файл obips.map.js можно скачать здесь.

Оптимизировать ли его обратно – решать вам. Я предпочел пока оставить его в «разобранном» виде. Так как править его, возможно, придется часто.

2. Изменив файл недостаточно просто очистить кеш браузера. Измененный JS-не подхватится.

Потребуется очистить кеш Weblogic Server’а: остановите его, удалите папку …Middleware/user_projects/domains/bifoundation_domain/servers/bi_server1/tmp
(либо скопируйте в эту папку измененный файл obips.map.js; у меня это папка /u01/app/Middleware/user_projects/domains/bifoundation_domain/servers/bi_server1/tmp/_WL_user/analytics_11.1.1/7dezjl/war/res/b_mozilla/views/map ), запустите WLS.

3. Очистите кеш браузера, если еще не делали этого.
4. Посмотрите на созданный ранее ансвер с картой.

Вот так симпатично получилось (естественно, следует помнить, что для отображения тайлов от OSM вам нужен доступ в интернет).

11 комментариев:

  1. Что за ошибка выскакивает при попытке выполнить:
    update STPETER_ADMIN_A_3785 set geometry = sdo_cs.transform(geometry,'USE_SPHERICAL', 3785);
    *
    ERROR at line 1:
    ORA-06553: PLS-307: too many declarations of 'TRANSFORM' match this call

    ОтветитьУдалить
  2. Андрей, наверняка, версия БД у вас не 11.2.
    (кстати, в версии 11.2.0.2 появилась возможность обойтись без этой опции - http://www.oraclegis.com/blog/?p=2077).

    Как вариант, высылайте мне дамп с вашей табличкой - я ее трансформирую и перешлю обратно. Либо попробуйте сами на тестовой БД 11.2

    ОтветитьУдалить
  3. Да версия 10.0.2.4 Также вместо Oracle Spatial стоит Intermedia.
    Пошел по немного другому пути как тут:http://sproke.blogspot.com/2009/03/howto-open-street-map-in-oracle.html#Loading OSM from PostgreSQL

    Осталось пару вопросов. Если можете подскажите
    1) Где находятся эти SRID и как это посмотреть
    2) ПРобовали ли в качестве вебсервера чтото еще кроме Mapviewer. Боюсь он мне не по карману.

    ОтветитьУдалить
  4. При попытке настройки mapviewer (п.6.) созданние подключения выдаёт:

    Data source cannot be created : MAPVIEWER-00011: Ошибка при создании источника данных карт.

    Аналогичная проблема была при подключении БД с примерами mvdemo, помог только ручной запуск скриптов mcsdefinition.sql и mvdemo.sql, после поднятия дампа mvdemo.dmp.

    Подскажите, в чем может быть проблема?

    ОтветитьУдалить
  5. Этот комментарий был удален автором.

    ОтветитьУдалить
  6. Можно ли как-нибудь подцепить OSM-стили для shp-файлов, которые импортируются в базу?
    Т.е например у меня есть SLD-файл стиля из geoserver могу ли я применить его к описанному вами способу?

    ОтветитьУдалить
  7. Подскажите в пункте 4
    когда "Добавим привязку слоя к ключу таблицы D_SPB_ADM_REGIONS"
    поле "Ключ слоя" пустой! В чем может быть причина?

    ОтветитьУдалить
    Ответы
    1. На этапе 1. Создадим геометрическую тему.
      Нужно в вкладке advance надо заполнить
      Key column и info column

      Удалить
  8. Карта есть, а раскраски нет, все белое, в чем может быть причина?

    ОтветитьУдалить
    Ответы
    1. Проверьте есть ли у пользователя ORACLE, через которого работает MapViewer, привилегия CREATE TYPE.

      Удалить
  9. Этот комментарий был удален автором.

    ОтветитьУдалить