0
votes

Requête spatiale Maximo / SIG

J'ai un bon de travail dans Maximo 7.6.1.1:

  • L'OE a les coordonnées LatitudeY et LongitudeX dans l'onglet Adresse du service.
  • L'OE dispose d'un champ zone personnalisé.

Et il y a une classe d'entités (polygones) dans une base de données SIG séparée.

Je souhaite effectuer une requête spatiale pour renvoyer un attribut de l ' enregistrement polygonal que l'OD croise et l'utiliser pour renseigner la zone dans le WO.

Comment puis-je faire cela?

Mot clé associé: Maximo Spatial


5 commentaires

Pouvez-vous demander à Maximo d'exécuter une instruction SQL personnalisée? Si oui, vous pouvez simplement lui faire exécuter une instruction SELECT qui retournera l'id de la zone qui contient votre point.


@AlbertGodfrind Bonne idée. Je n'en sais pas encore assez sur la personnalisation Maximo pour répondre à cela. J'ai posé une question distincte sur faisant référence à un Fonction Oracle , mais on lui a dit que ce serait une mauvaise pratique.


Ah les mauvaises pratiques. Ou de bonnes pratiques. J'ai lu tellement de livres et de documents de conférence où les auteurs poussent leur propre idée de ce qu'est une «bonne» ou «mauvaise» pratique. Vous voudrez peut-être demander pourquoi invoquer exactement un SELECT est une mauvaise pratique ...


D'autre part, il existe une possibilité qui ne nécessite aucun changement dans Maximo: il suffit d'ajouter un déclencheur sur la table des bons de travail, qui remplira automatiquement la colonne de zone chaque fois qu'un bon de travail est inséré (ou l'emplacement d'un bon de travail existant est modifié) . Ce déclencheur a juste besoin de récupérer l'id de la zone contenant l'emplacement de l'ordre de travail à l'aide d'un simple SELECT.


Je ne peux pas donner les détails pour être considéré comme une réponse, mais j'ai utilisé le script d'automatisation de Maximo pour appeler un service de géocodage inversé ArcGIS via son API REST sur HTTPS. Je lui ai envoyé un point (lat / long), et il m'a rendu ce qu'il y avait dans JSON. Scripting 76 Fonctionnalités a beaucoup aidé.


3 Réponses :


2
votes

Faire cela en direct dans Maximo en utilisant un script d'automatisation est possible ou en écrivant du code personnalisé dans Spatial (plus difficile). Vous souhaitez utiliser l'outil / MapServer / identifier et publier la géométrie xy, le système de coordonnées et la couche que vous souhaitez interroger. fenêtre d'identification

Vous devrez formater correctement l'objet géométrie et tester votre message depuis la fenêtre. Je récupère généralement le message dans la section réseau des outils de développement une fois que je le fais fonctionner et que je change le format de sortie en json et que je l'utilise dans mon code.


0 commentaires

1
votes

Vous n'aurez peut-être pas du tout besoin de toucher à votre environnement Maximo. Que diriez-vous d'utiliser simplement un déclencheur sur votre table des bons de travail? Ce déclencheur peut ensuite remplir automatiquement l'ID de zone à partir d'une simple instruction de sélection qui correspond à x et y avec les zones de la table des zones. Voici à quoi cela pourrait ressembler.

Cela suppose que vos bons de travail sont dans un tableau comme celui-ci:

update work_orders set x=x, y=y;

et les zones dans un tableau comme celui-ci p >

create or replace trigger work_orders_fill_zone
  before insert or update of x,y on work_orders
  for each row
begin
  select zone_id
  into :new.zone_id
  from zones
  where sde.st_contains (zone_shape, sde.st_point (:new.x, :new.y, 4326) ) = 1;
end;
/

Ensuite, le déclencheur serait comme ceci

create table zones (
  zone_id number primary key,
  shape st_geometry
)

Quelques hypothèses:

  1. Les colonnes x et y contiennent des coordonnées en longitude / latitude WGS84 (pas dans une projection ou dans un autre système de coordonnées long / lat)

  2. Les zones ne se chevauchent pas: un point de bon de travail est donc toujours dans une et une seule zone. Sinon, la requête peut renvoyer plusieurs résultats, que vous devrez ensuite gérer.

  3. Les zones couvrent entièrement le territoire dans lequel vos bons de travail peuvent avoir lieu. Si un emplacement de bon de travail peut être en dehors de toutes vos zones, vous devez également le gérer (la requête ne renvoie aucun résultat). >

  4. Les colonnes x et y sont toujours remplies. S'ils sont facultatifs, vous devez également gérer ce cas (définissez zone_id sur NULL si x ou y code > est NULL )

Après cela, chaque fois qu'un nouvel ordre de travail est inséré dans la table work_orders , la colonne zone_id sera automatiquement mise à jour.

Vous pouvez initialiser zone_id dans vos bons de travail existants avec une simple mise à jour:

create table work_orders (
  wo_id number primary key,
  x number,
  y number,
  zone_id number
);

Cela fera exécuter le déclencheur pour chaque ligne du tableau ... Cela peut prendre un certain temps si le tableau est volumineux.


1 commentaires

Maximo a sa logique métier dans des classes Java, en dehors de la base de données. Ces classes valident les données, effectuent un travail supplémentaire lors de la validation des données, enregistrent des pistes d'audit et envoient des mises à jour à des systèmes externes intégrés, entre autres. Ainsi, bien que cette réponse soit de bonne qualité et montre beaucoup d'efforts, l'utilisation de déclencheurs de base de données est fortement déconseillée aux développeurs Maximo. Les scripts d'automatisation sont destinés à remplacer le besoin de déclencheurs de base de données.



1
votes

Adaptez le code de la section Scripts de bibliothèque de Maximo 76 Script> Fonctionnalités (pdf):

from psdi.iface.router import HTTPHandler
from java.util import HashMap
from java.lang import String

handler = HTTPHandler()
map = HashMap()
map.put("URL", url)
map.put("HTTPMETHOD", "GET")
responseBytes = handler.invoke(map, None)
response = String(responseBytes, "utf-8")

LIBHTTPCLIENT: (un Jython réutilisable script de la bibliothèque )

#What the script does:
#     1. Takes the X&Y coordinates of a work order in Maximo
#     2. Generates a URL from the coordinates
#     3. Executes the URL via a separate script/library (LIB_HTTPCLIENT)
#     4. Performs a spatial query in an ESRI REST feature service (a separate GIS system)
#     5. Returns JSON text to Maximo with the attributes of the zone that the work 
#        order intersected
#     6. Parses the zone number from the JSON text
#     7. Inserts the zone number into the work order record

from psdi.mbo import MboConstants
from java.util import HashMap
from com.ibm.json.java import JSONObject

field_to_update = "ZONE"
gis_field_name = "ROADS_ZONE"

def get_coords():
    """
    Get the y and x coordinates(UTM projection) from the WOSERVICEADDRESS table
    via the SERVICEADDRESS system relationship.
    The datatype of the LatitdeY and LongitudeX fields is decimal.
    """
    laty  = mbo.getDouble("SERVICEADDRESS.LatitudeY")
    longx = mbo.getDouble("SERVICEADDRESS.LongitudeX")

    #Test values
    #laty  = 4444444.7001941890
    #longx = 666666.0312127020

    return laty, longx


def is_latlong_valid(laty, longx):
    #Verify if the numbers are legitimate UTM coordinates
    return (4000000 <= laty <= 5000000 and
            600000 <= longx <= 700000)


def make_url(laty, longx, gis_field_name):
    """
    Assembles the URL (including the longx and the laty).
    Note: The coordinates are flipped in the url.
    """

    url = (
        "http://hostname.port"
        "/arcgis/rest/services/Example"
        "/Zones/MapServer/15/query?"
        "geometry={0}%2C{1}&"
        "geometryType=esriGeometryPoint&"
        "spatialRel=esriSpatialRelIntersects&"
        "outFields={2}&"
        "returnGeometry=false&"
        "f=pjson"
    ).format(longx, laty, gis_field_name)

    return url


def fetch_zone(url):
    # Get the JSON text from the feature service (the JSON text contains the zone value).
    ctx = HashMap()
    ctx.put("url", url)
    service.invokeScript("LIBHTTPCLIENT", ctx)
    json_text = str(ctx.get("response"))

    # Parse the zone value from the JSON text
    obj = JSONObject.parse(json_text)
    parsed_val = obj.get("features")[0].get("attributes").get(gis_field_name)

    return parsed_val


try:
    laty, longx = get_coords()
    if not is_latlong_valid(laty, longx):
        service.log('Invalid coordinates')
    else:
        url = make_url(laty, longx, gis_field_name)
        zone = fetch_zone(url)

        #Insert the zone value into the zone field in the work order
        mbo.setValue(field_to_update, zone, MboConstants.NOACCESSCHECK)
        service.log(zone)
except:
    #If the script fails, then set the field value to null.
    mbo.setValue(field_to_update, None, MboConstants.NOACCESSCHECK)
    service.log("An exception occurred")


0 commentaires