[własne] Semantic Maps - Use Case

Zespół

  • Olgierd Grodzki

Opis

Wymagania

//(C) - koncept, (I) - instancja
Obiekt (C)
   | --- Beacon (C)
   |       | --- beacon1 (I)
   |       | --- beacon2 (I)
   |       | --- beacon3 (I)
   |       | --- beacon4 (I)
   |
   | --- POI (C)
           | --- krzesło (I)
           | --- stół (I)
           | --- komputer (I)
          ...
  • powiązanie obiektów z beaconami (przykład):
    • POI jest_przypisany_do exactly 1 Beacon (POI należy do 1 Beacona)
    • Beacon ma_przypisane only POI (do Beacona można przypisać tylko POI; 0 lub więcej)
  • POI ma tagi:
    • POI ma_tag only String (do POI można przypisać 0 lub więcej Stringów)
  • Wnioskowanie (propozycja):
    1. na wejściu: aktualny Beacon
    2. wyciągamy POI, które są do niego przypisane
    3. wyciągamy tagi z tych POI
    4. szukamy innych POI z takimi tagami
    5. sprawdzamy do których Beaconów są przypisane znalezione POI
    6. wyświetlamy te Beacony na mapce

Spotkania

20141217

Spotkanie organizacyjne

Projekt

Ontologia

Aby zrealizować postawione wymagania konieczne było zmodyfikowanie ontologii SemanticMaps. Do ontologii dodano następujące DatatypeProperty identyfikujące Beacona:

<owl:DatatypeProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasUUID">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#Beacon"/>
    <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
 
<owl:DatatypeProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasMajor">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#Beacon"/>
    <rdfs:range rdf:resource="&xsd;positiveInteger"/>
</owl:DatatypeProperty>
 
<owl:DatatypeProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasMinor">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#Beacon"/>
    <rdfs:range rdf:resource="&xsd;positiveInteger"/>
</owl:DatatypeProperty>

Dodano także następujące DatatypeProperty opisujące POI w kontekście tego projektu:

<owl:DatatypeProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasName">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#POI"/>
    <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
 
<owl:DatatypeProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasTag">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#POI"/>
    <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>

Następnie zamodelowano powiązanie Beaconów z POI, zgodnie z wymaganiami stworzono relacje „w obie strony” przy pomocy następujących ObjectProperty:

<owl:ObjectProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#hasPOI">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#Beacon"/>
    <rdfs:range rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#POI"/>
</owl:ObjectProperty>
 
<owl:ObjectProperty rdf:about="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#isAssignedToBeacon">
    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
    <rdfs:domain rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#POI"/>
    <rdfs:range rdf:resource="http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#Beacon"/>
</owl:ObjectProperty>

Na koniec postanowiono stworzyć instancje. Ponieważ realizator projektu posiada tylko 2 beacony, stworzono 2 instancje klas Beacon i 2 instancje klas POI przypisane do odpowiednich beaconów:

<POI rdf:ID="POI1">
    <hasName rdf:datatype="&xsd;string">Old table</hasName>
    <hasTag rdf:datatype="&xsd;string">antique</hasTag>
    <isAssignedToBeacon rdf:resource="#Beacon1"/>
</POI>
 
<POI rdf:ID="POI2">
    <hasName rdf:datatype="&xsd;string">Old chair</hasName>
    <hasTag rdf:datatype="&xsd;string">antique</hasTag>
    <isAssignedToBeacon rdf:resource="#Beacon2"/>
</POI>
 
<Beacon rdf:ID="Beacon1">
    <hasUUID rdf:datatype="&xsd;string">F7826DA6-4FA2-4E98-8024-BC5B71E0893E</hasUUID>
    <hasMajor rdf:datatype="&xsd;positiveInteger">64903</hasMajor>
    <hasMinor rdf:datatype="&xsd;positiveInteger">35944</hasMinor>
    <hasPOI rdf:resource="#POI1"/>
</Beacon>
 
<Beacon rdf:ID="Beacon2">
    <hasUUID rdf:datatype="&xsd;string">F7826DA6-4FA2-4E98-8024-BC5B71E0893E</hasUUID>
    <hasMajor rdf:datatype="&xsd;positiveInteger">54294</hasMajor>
    <hasMinor rdf:datatype="&xsd;positiveInteger">26255</hasMinor>
    <hasPOI rdf:resource="#POI2"/>
</Beacon>

Zmodyfikowana w ten sposób ontologia znajduje się w pliku concepts.owl.zip i jest wykorzystywana na dalszych etapach projektu.

SPARQL

Aby „wyciągnąć” potrzebne informacje z ontologii wykorzystano SPARQL. Do testowania kwerend wykorzystano poznane na laboratorium narzędzie Twinkle.

Proces „wyciągania” informacji, przedstawiony w sekcji Wymagania w postaci kolejnych kroków, postanowiono podzielić na 2 etapy wraz z odpowiadającymi im kwerendami. Jako pierwszy etap przyjęto „wyciąganie” tagów z POI przypisanych do wejściowego beacona, a jako drugi „wyciąganie” danych beaconów które posiadają przypisane POI opisane „wyciągniętymi” wcześniej tagami. Przykładowa kwerenda realizująca pierwszy etap może być przedstawiona następująco:

PREFIX semmap: <http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#>

SELECT DISTINCT ?poitag
WHERE {
    ?b a semmap:Beacon.
    ?b semmap:hasUUID ?uuid.
    ?b semmap:hasMajor ?major.
    ?b semmap:hasMinor ?minor.
    FILTER (regex(?uuid, "F7826DA6-4FA2-4E98-8024-BC5B71E0893E") && ?major = 64903 && ?minor = 35944)
    ?b semmap:hasPOI ?poi.
    ?poi semmap:hasTag ?poitag.
}

Wykonanie tej kwerendy na zmodyfikowanej ontologii zwraca następujący wyniki:

--------------------------------------------------------
| poitag                                               |
========================================================
| "antique"^^<http://www.w3.org/2001/XMLSchema#string> |
--------------------------------------------------------

Jest to wynik zgodny z oczekiwaniami i zgodny z przedstawioną modyfikacją ontologii. W drugim etapie zwrócone tagi są wykorzystywane do znalezienia beaconów zawierających POI opisane tymi tagami. Przykładowa kwerenda realizująca ten etap dla zwróconego tagu przedstawionego powyżej może być przedstawiona następująco:

PREFIX semmap: <http://www.semanticweb.org/agh/wshop/semanticmaps/Concepts#>

SELECT DISTINCT ?uuid ?major ?minor
WHERE {
    ?p a semmap:POI.
    ?p semmap:hasName ?poiname.
    ?p semmap:hasTag ?poitag
    FILTER (regex(?poitag, "antique"))
    ?p semmap:isAssignedToBeacon ?b.
    ?b semmap:hasUUID ?uuid.
    ?b semmap:hasMajor ?major.
    ?b semmap:hasMinor ?minor.
}

Wykonanie tej kwerendy na zmodyfikowanej ontologii zwraca następujący wyniki:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| uuid                                                                              | major                                                       | minor                                                       |
=================================================================================================================================================================================================================
| "F7826DA6-4FA2-4E98-8024-BC5B71E0893E"^^<http://www.w3.org/2001/XMLSchema#string> | "54294"^^<http://www.w3.org/2001/XMLSchema#positiveInteger> | "26255"^^<http://www.w3.org/2001/XMLSchema#positiveInteger> |
| "F7826DA6-4FA2-4E98-8024-BC5B71E0893E"^^<http://www.w3.org/2001/XMLSchema#string> | "64903"^^<http://www.w3.org/2001/XMLSchema#positiveInteger> | "35944"^^<http://www.w3.org/2001/XMLSchema#positiveInteger> |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Wynik również jest zgodny z oczekiwaniami i zgodny z przedstawioną modyfikacją ontologii. Jak widać, zwrócony został także wejściowy beacon, nie jest jednak problemem odrzucenie go w aplikacji wykorzystującej to rozwiązanie.

Dzięki przedstawionemu zestawowi dwóch kwerend SPARQL zrealizowane są wszystkie przedstawione w sekcji Wymagania kroki propozycji wnioskowania poza ostatnim.

Fuseki

Zgodnie z ustaleniami ze spotkania organizacyjnego praktyczne rozwiązanie postanowiono zaprojektować zgodnie z architekturą klient-serwer, z „wiedzą” w postaci ontologii dostępną na serwerze oraz aplikacją mobilną wysyłającą zapytania do tego serwera. Jako serwer wybrano Apache Jena Fuseki, wspierający RESTowy SPARQL.

Integracja wypracowanego do tego etapu rozwiązania w postaci zamieszczonej ontologii z serwerem okazała się być trywialna i sprowadziła się do załadowania pliku owl przez Control Panel serwera w przeglądarce. Interfejs webowy serwera udostępnia także możliwość testowania kwerend SPARQL i zwracania ich w różnych formatach. Aby zweryfikować poprawną integrację postanowiono przetestować zamieszczone kwerendy na serwerze Fuseki.

Import zamieszczonej ontologii do Fuseki przebiegł pomyślnie:

Wykonanie pierwszej kwerendy

zwróciło następujący wynik (przedstawiony w JSON gdyż w ten sposób będzie realizowana komunikacja z klientem):

{
  "head": {
    "vars": [ "poitag" ]
  } ,
  "results": {
    "bindings": [
      {
        "poitag": { "datatype": "http://www.w3.org/2001/XMLSchema#string" , "type": "typed-literal" , "value": "antique" }
      }
    ]
  }
}

Jest to wynik zgodny z wynikiem otrzymanym z Twinkle. Wykonanie drugiej kwerendy

zwróciło następujący wynik:

{
  "head": {
    "vars": [ "uuid" , "major" , "minor" ]
  } ,
  "results": {
    "bindings": [
      {
        "uuid": { "datatype": "http://www.w3.org/2001/XMLSchema#string" , "type": "typed-literal" , "value": "F7826DA6-4FA2-4E98-8024-BC5B71E0893E" } ,
        "major": { "datatype": "http://www.w3.org/2001/XMLSchema#positiveInteger" , "type": "typed-literal" , "value": "64903" } ,
        "minor": { "datatype": "http://www.w3.org/2001/XMLSchema#positiveInteger" , "type": "typed-literal" , "value": "35944" }
      } ,
      {
        "uuid": { "datatype": "http://www.w3.org/2001/XMLSchema#string" , "type": "typed-literal" , "value": "F7826DA6-4FA2-4E98-8024-BC5B71E0893E" } ,
        "major": { "datatype": "http://www.w3.org/2001/XMLSchema#positiveInteger" , "type": "typed-literal" , "value": "54294" } ,
        "minor": { "datatype": "http://www.w3.org/2001/XMLSchema#positiveInteger" , "type": "typed-literal" , "value": "26255" }
      }
    ]
  }
}

Jest to wynik również zgodny z wynikiem otrzymanym z Twinkle. Dzięki temu ontologia zyskała dostęp w postaci SPARQL przez HTTP.

Aplikacja mobilna

Aplikacja mobilna komunikuje się z serwerem Fuseki za pomocą zamieszczonych kwerend SPARQL, uzupełnianych o rzeczywiste dane, przekazywanych jako parametry w query string. Kwerendy budowane są za pomocą biblioteki sparql-java, danymi uzupełnianymi są w przypadku pierwszej kwerendy uuid, major i minor rzeczywistego beacona, a przypadku drugiej kwerendy tag.

Beacon wejściowym jest wybierany z listy dostępnych beaconów na podstawie RSSI - beacon o największej sile sygnału jest uznawany za najbliższy i podawany na wejście algorytmu. Odpowiedź serwera w postaci JSONa jest odczytywana ze strumienia i parsowana za pomocą klas z pakietu org.json dostępnego w API Androida. Na podstawie przeparsowanej odpowiedzi tworzona jest lista „podobnych” beaconów.

W warstwie prezentacji aplikacji najważniejszym elementem jest mapa. Mapy tworzone i wyświetlane są przy pomocy biblioteki micromap. Wstępnie beacon najbliższy jest oznaczany na mapie większą, wyboldowaną czcionką a beacony „podobne” tą samą, większą czcionką ale nie wyboldowaną.

Prosty scenariusz wykorzystania rozwiązania można zobaczyć na nagraniu z aplikacji - semmap_usecase1.zip. Wyświetlona mapka przedstawia pokój realizatora projektu, eksperyment był wykonywany w pobliżu lewego górnego rogu mapki. Na początku nagrania wyświetlone są dane beaconów (uuid, major i minor), które można porównać z zamieszczoną ontologią. Następnie wykorzystana jest funkcja znajdowania najbliższego beacona, beacon znajdujący się w górze mapki zostaje poprawnie wybrany jako najbliższy i zaznaczony większą, wyboldowaną czcionką. Na koniec wykorzystana jest funkcja znajdowania beaconów „podobnych” - pierwsza kwerenda zostaje uzupełniona danymi najbliższego beacona, następuje komunikacja z serwerem, zwrócona zostaje jednoelementowa lista tagów zawierająca element „antique”, druga kwerenda zostaje uzupełniona tagiem „antique”, następuje komunikacja z serwerem, zwrócona zostaje dwuelementowa lista beaconów z której usunięty zostaje beacon wejściowy, pozostały beacon zostaje zaznaczony większą, niewyboldowaną czcionką.

Aktualnie zaimplementowany i przedstawiony na nagraniu sposób wykorzystania rozwiązania i wyświetlania beaconów na mapie jest jedynie wstępną propozycją, przydatną do zaprezentowania działania rozwiązania. Jest to jednak sposób mało praktyczny i mało atrakcyjny wizualnie, w ramach propozycji dalszych prac zaproponować można usprawnienie warstwy prezentacyjnej i UX rozwiązania.

Sprawozdanie

Projekt Gradle pluginu aware-beacons-v2 (branch semweb) - aware-beacons-semweb.zip

Materiały

pl/dydaktyka/semweb/2014/projects/semmap-usecase.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0