OrientDB ETL edge lookup from query - how to access $input? - graph

I'm trying my darnedest to do an ETL import from a large dataset that I've been keeping in MongoDB. I've successfully imported the vertices, and I feel like I'm one little syntax misunderstanding away from importing the edges too.
I am pretty sure that the error is in this transformer:
{"edge":{"class":"Friend", "joinFieldName":"id",
"lookup": "select from Character WHERE $input.id IN character_friends",
"unresolvedLinkAction":"CREATE"}},
So what I'm trying to do is to make an edge from a document with id = FOO to all other documents that contain FOO in their character_friends array.
If I execute
select from Character WHERE FOO IN character_friends
in the browser, I get a ton of documents, so my guess is that my problem is with $input.id either not returning the id I'm expecting, or maybe not being recognized as a variable at all.
Documents look like this:
{
id: FOO,
character_friends: [BAR, BAZ, QUX]
(and a bunch of other junk)
}

Seems you're inserting a property "id", but it's reserved in Blueprints standard. You can rename it (with "field" transformers) or set this in Orient Loader:
standardElementConstraints: false,
Then I've created the file /temp/datasets/charles.json with this content:
[
{
name: "Joe",
id: 1,
friends: [2,4,5],
enemies: [6]
},
{
name: "Suzie",
id: 2,
friends: [1,4,6],
enemies: [5,2]
}
]
And this pipeline:
{
config: {
log: "debug",
parallel: false
},
source : {
file: { path: "/temp/datasets/charles.json", lock : true }
},
extractor : {
json: {}
},
transformers : [
{ merge: { joinFieldName:"id", lookup:"Account.id" } },
{ vertex: { class: "Account"} },
{ edge: {
"class": "Friend",
"joinFieldName": "friends",
"lookup": "Account.id",
"unresolvedLinkAction": "CREATE"
} },
{ edge: {
"class": "Enemy",
"joinFieldName": "enemies",
"lookup": "Account.id",
"unresolvedLinkAction": "CREATE"
} }
],
loader : {
orientdb: {
dbURL: "plocal:/temp/databases/charles",
dbUser: "admin",
dbPassword: "admin",
dbAutoDropIfExists: true,
dbAutoCreate: true,
standardElementConstraints: false,
tx: false,
wal: false,
batchCommit: 1000,
dbType: "graph",
classes: [{name: 'Account', extends:"V"}, {name: 'Friend', extends:"E"}, {name: 'Enemy', extends:"E"}],
indexes: [{class:"Account", fields:["id:integer"], type:"UNIQUE_HASH_INDEX" }]
}
}
}
Assure to use last version of ETL jar (replace it in $ORIENTDB/lib) with default version. Last version is downloadable from:
https://oss.sonatype.org/content/repositories/snapshots/com/orientechnologies/orientdb-etl/2.0.2-SNAPSHOT/orientdb-etl-2.0.2-20150208.225903-1.jar
Or get OrientDB ETL 2.0.2 of major.

Related

View not displaying Model Data from Manifest.json

I'm trying to setup my app descriptor file (manifest.json) to include a named model, 'inputs' in its "models" object. From my understanding, after doing so, the model should be available throughout the app when provided the correct path (see XML View).
The reason I'd like to setup this manifest.json is because it's a best practice to configure all models in here.
In the controller, I'd like to get and then set the 'inputs' Model defined in the manifest.json --but how can this be done?
manifest.json (Where I have configured the 'inputs' model)
{
"_version": "1.1.0",
"sap.app": {
"_version": "1.1.0",
"id": "pricingTool",
"type": "application",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"ach": "ach",
"resources": "resources.json",
"sourceTemplate": {
"id": "ui5template.basicSAPUI5ApplicationProject",
"version": "1.30.3"
},
},
"sap.ui": {
"_version": "1.1.0",
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"_version": "1.1.0",
"rootView": {
"viewName": "pricingTool.view.Main",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {}
}
},
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"inputs": {
"type": "sap.ui.model.json.JSONModel",
"uri": "model/inputs.json"
},
},
}
Main.controller.js (where the 'inputs' model should be set from the manifest file)
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel',
'sap/ui/model/Filter',
'sap/ui/model/FilterOperator',
'sap/m/MessageToast',
'pricingTool/model/viewControls',
'pricingTool/model/formatter',
'pricingTool/model/Utility',
'sap/ui/core/util/Export',
'sap/ui/core/util/ExportTypeCSV',
],
function (jQuery, Controller, JSONModel, Filter, FilterOperator, MessageToast, viewControls, formatter, Utility, Export, ExportTypeCSV) {
"use strict";
var mainController = Controller.extend("pricingTool.controller.Main", {
onInit: function(oEvent) {
//define named/default model(s)
var inputs = new JSONModel("./model/inputs.json");
//set model(s) to current xml view
this.getView().setModel(inputs, "inputs");
//this is one solution I have tried, but doesn't do anything:
// this.getView().setModel(this.getOwnerComponent().getModel("inputs"), "inputs");
//another solution I have tried:
//var inputs = this.getModel('input') <--I was hoping this would find the inputs defined in the manifest.json, but this doesn't work either
// this.getView().setModel(inputs, "inputs");
},
...
inputs.json
{
"propA" : "testVal"
}
XML View
<Button text="{inputs>propA}"></Button>
Components.js (Not sure what to do in the Component.js)
sap.ui.define([
'sap/ui/core/UIComponent'
],
function(UIComponent) {
"use strict";
var Component = UIComponent.extend("pricingTool.Component", {
metadata : {
metadata : {
manifest: "json"
},
rootView : "pricingTool.view.Main",
dependencies : {
libs : [
"sap.m",
"sap.ui.layout"
]
},
config : {
sample : {
files : [
"Main.view.xml",
"Main.controller.js"
]
}
}
},
init : function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
}
});
return Component;
});
The problem is that the model property ("propA") is not displaying when I test it on a button control. Can anyone tell me why the model is not displaying in the app?
Summarizing Question
How can I define a model in manifest.json, and then set that model in the controller so I can use it in my xml view?
try putting a forward slash before your property name...
<Button text="{inputs>/propA}"></Button>
...and update your manifest file so that your model definition points to your dataSource defined under sap.app as follows...
{
"_version": "1.1.0",
"sap.app": {
"_version": "1.1.0",
"id": "pricingTool",
"type": "application",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"ach": "ach",
"resources": "resources.json",
"sourceTemplate": {
"id": "ui5template.basicSAPUI5ApplicationProject",
"version": "1.30.3"
},
"dataSources": {
"inputsData": {
"type" : "JSON",
"uri": "model/inputs.json"
}
}
},
"sap.ui": {
"_version": "1.1.0",
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"_version": "1.1.0",
"rootView": {
"viewName": "pricingTool.view.Main",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"products": {
"type": "sap.ui.model.json.JSONModel",
"uri": "model/products.json"
},
"inputs": {
"type": "sap.ui.model.json.JSONModel",
"dataSource" : "inputsData"
}
}
}
}
...change your Component.js file to point to your manifest file...
sap.ui.define([
'sap/ui/core/UIComponent'
],
function(UIComponent) {
"use strict";
var Component = UIComponent.extend("pricingTool.Component", {
metadata : {
manifest: "json",
},
init : function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
}
});
});
... and remove the onInit logic within your controller to set the model (this is handled by the component)
Those models you define in the manifest.json file are created in the Component context (if your app based on Component). To make it available in the XML view you have to obtain it from Component and then attach to the view. The code snippet you can use in onInit controller event looks like this:
this.getView().setModel(this.getOwnerComponent().getModel("<your_model_name>"), "<your_model_name>");
if you are using standard template then most likely you have a BaseController as an ancestor, in that case the code can look shorter:
this.setModel(this.getComponentModel("<your_model_name>"), "<your_model_name>");
Here is a minimal example of what you'd like to achieve: https://embed.plnkr.co/l1XF5O/
Models defined in manifest.json (aka. "app descriptor") will be set to the component (since v1.30).
If a descriptor is used, almost all properties of your component's metadata other than manifest: "json" are deprecated and should be avoided. Deprecated properties are listed here.
Views (and their controls inside) inside the root view instantiated by your component inherit models automatically from the component. Thus, setting models to your view explicitly is not needed anymore. Your view already knows the model that is set to the component.*
The binding syntax should be used correctly according to your situation:
Use relative binding syntax (modelName>property) only if a parent control has already a context bound (e.g. the parent control uses aggregation binding, or element binding).
In other cases, use absolute binding syntax. It starts with a slash (modelName>/property), so that the control doesn't look for the binding context of its parent.
*Although the model, which is set on the component, can be used seamlessly in the XMLView, retrieving the component model by calling view.getModel inside the onInit handler will return undefined. More about this: https://stackoverflow.com/a/43941380/5846045

Alfresco Aikau - creating list for view

I have been working through the Aikau tutorials on Github but can't work out how to create a list that I can pass on to a view. The requirement is to select all workflow tasks for all users and display the results.
I have added the following widgets which displays the details of one users(hard coded), but I need to cycle through all the users and display all workflows.
model.jsonModel = {
services: [
"alfresco/services/CrudService"
],
widgets:[
{
name: "alfresco/lists/AlfSortablePaginatedList",
config: {
loadDataPublishTopic: "ALF_CRUD_GET_ALL",
loadDataPublishPayload: {
url: "api/task-instances?authority=abeecher"
},
itemsProperty: "data",
widgets: [
{
name: "alfresco/lists/views/AlfListView",
config: {
additionalCssClasses: "bordered",
widgetsForHeader: [
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Workflow ID",
sortable: true,
sortValue: "id"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Description"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Status"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Due Date",
sortable: true,
sortValue: "properties.bpm_dueDate"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Created By"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Assigned To",
sortable: true,
sortValue: "owner.firstName"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Tag1"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Tag2"
}
},
{
name: "alfresco/lists/views/layouts/HeaderCell",
config: {
label: "Tag3"
}
}
],
widgets: [
{
name: "alfresco/lists/views/layouts/Row",
config: {
widgets: [
{
name: "alfresco/lists/views/layouts/Cell",
config: {
additionalCssClasses: "mediumpad",
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "id",
}
}
]
}
},
{
name: "alfresco/lists/views/layouts/Cell",
config: {
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "workflowInstance.message",
}
}
]
}
},
{
name: "alfresco/lists/views/layouts/Cell",
config: {
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "state",
}
}
]
}
},
{
name: "alfresco/lists/views/layouts/Cell",
config: {
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "properties.bpm_dueDate",
}
}
]
}
},
{
name: "alfresco/lists/views/layouts/Cell",
config: {
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "workflowInstance.initiator.firstName" ,
}
}
]
}
},
{
name: "alfresco/lists/views/layouts/Cell",
config: {
widgets: [
{
name: "alfresco/renderers/Property",
config: {
propertyToRender: "owner.firstName",
}
}
]
}
},
]
}
}
]
}
}
]
}
}
]
};
The final solution will require the ability to sort the columns and be able to click on a task to see the underlying workflow. What would be the best way to create the initial list based on these requirements?
If I was to write a widget that did the building of the list, how do I couple the widget to the form? Is this a pub/sub solution since the user is not clicking on anything - just loading the page?
I assume that I would need to write custom a webscript if I use the "url" keyword under the loadDataPublishPayload option? If I did write a webscript, what would be the final statement to return the json data to the form?
I just need some guidance on the best way forward.
At the time of writing, using the latest released version of Aikau (1.0.83) it is not possible to do this using out-of-the-box widgets and services.
The main problem is that there is no full mapping between Aikau and the Share XML based forms runtime. This blog post explains the issue at hand. It is however something that we're working on.
Once the "alfresco/services/FormsRuntimeService" is complete this will be an easier exercise to complete. There would be no need to write additional widgets for the lists because the existing list widgets handle all the requirements for sorting/pagination (if the underlying REST API supports sorting and pagination!).
I guess your best way forward is very dependent upon how quickly require this solution. We're making progress with the FormsRuntimeService, but I can't say when it will be fully ready.
The existing pages in Share that show tasks and workflow that do use the Share Forms Runtime rely on APIs that return HTML that is hard-coded to work with the Share YUI2 based widgets - it might be possible to achieve what you want to using the older Surf Component / YUI2 widget approach. That might be one other area to explore.
The main thing to do is to establish whether or not there are existing REST APIs that will meet you core requirements

How do you query data by with multiple conditions or indexes?

I'm trying to design a performant NoSQL schema for my Firebase application, but how would I query multiple checkpoints which have a unique tag?
Consider the following rules:
Tiers can have multiple tags
Tags can have multiple Checkpoints
Tag keys (names) are unique for each tier
Checkpoints can have multiple tags, but only 1 tag per tier
Here's what I have so far:
{
"tiers": {
"1": {
"web": true,
"android": true
},
"2": {
"basics": true,
"angular2": true,
"aurelia": true
},
"3": {
"basics": true,
"components": true
}
},
"tags" : {
"1": {
"web": {
"name": "Web Development",
"children": {
"front-end": true,
"angular2": true,
"aurelia": true
}
},
"android": {
"name": "Android Development",
"children": {
"front-end": true
}
}
},
"2": {
"front-end": {
"name": "Basics",
"parents": {
"web": true,
"android": true
},
"children": {
"angular2": true,
"aurelia": true,
"android-studio": true
}
}
},
"3": {
"angular2": {
"name": "Angular 2.x",
"parents": {...},
"children": {...}
},
"aurelia": {
"name": "Aurelia 1.x"
}
}
},
"checkpoints": {
"<randomKey>" : {
"name": "Angular 2 Quick Start",
"tags": {
"1": "web",
"2": "front-end",
"3": "angular2"
}
}
}
}
Right now I can query for all checkpoints under the Tier 1 web tag with:
ref.orderByChild('tags/1').equalTo("web").once('value', snap => console.log(snap.val()));
but since you can only define one indexOn rule, it's not optimized. At least if I can set the indexOn rule I can at least filter out most of the checkpoints then filter the rest in my code.
What can I do to efficiently query my checkpoints based on multiple tags AND the tiers?
Eventually I'd need to do a query for checkpoints with "tags": {"1": "web" AND "2": "front-end"} which I can't for the life of me figure out how to execute efficiently. I was thinking of doing another table with composite keys (e.g. each tier/tag contains references to ALL child checkpoints), but that would lead to requiring me to add and delete references within each tier.
There must be a better way.
I was vastly over complicating the solution - I ended up:
Removing Tier from the equation all together
Adding each checkpoint within each tag it was related to
Querying all checkpoints related to each selected tag and removing the ones which did not appear in each tag selected
Here's my new schema:
allTags = [
{"abc": true, "def": true, "hij": true},
{"abc": true, "def": true}
];
tags: [
{ "0": [
{"software-development": {name: "Software Development", checkpoints: [ {"abc": true}, {"def": true}, {"hij": true}]}}
]},
{"1": [
{"web": {name: "Web", checkpoints: [ {"abc": true}, {"def": true}]}},
{"android": {name: "Android", checkpoints: [{"hij": true}]}}
]}
];
checkpoints: [
{"abc": { name: "Angular2 Quick Start"}},
{"def": { name: "Building global directives in Angular2"}},
{"hij": { name: "Android Quick Start"}},
];
Creating a new Checkpoint:
public createCheckpoint(tags: any[], checkpoint: any) {
// push checkpoint
let checkpointRef = this.firebase.child('test/checkpoints');
let checkpointKey = checkpointRef.push(checkpoint).key(); // might have to do separate call
// Add checkpoint under each related tag
tags.forEach(tag => {
let tagRef = this.firebase.child('test/tags/' + tag.tier + '/' + tag.key + '/checkpoints/' + checkpointKey);
tagRef.set(true)
});
}
Retrieving all checkpoints based on selected tags:
public getCheckpointss(tags: any[]) {
// tag.tier, tag.key
let checkpointKeysToGet: string[] = [];
tags.forEach(tag => {
let ref = this.firebase.child('test/tags/' + tag.tier + '/' + tag.key + '/checkpoints');
ref.once('value', snap => {
let tagKeys:string[] = this.convertToArray(snap.val());
if (checkpointKeysToGet.length == 0){
checkpointKeysToGet = checkpointKeysToGet.concat(tagKeys);
}
else {
checkpointKeysToGet.forEach(existingTagKey => {
let tagKeysInBothTiers = tagKeys.filter(tagKey => {
return checkpointKeysToGet.includes(tagKey, 0)
});
checkpointKeysToGet = tagKeysInBothTiers;
console.log(checkpointKeysToGet);
});
}
});
});
}
All valid criticisms are welcome as long as you propose a solution to go along with it :)

PartialShardFailureException when trying to filter by GeoDistance (foselasticaBundle Symfony2)

For a few days my elastica query doesn't work anymore. I don't have problem to populate and if i remove the GeoDistance part the request is been executed and i get results. Currently, in the trace, I got the following message:
"message": "1",
"class": "Elastica\\Exception\\PartialShardFailureException",
"trace": [
{
"namespace": "",
"short_class": "",
"class": "",
"type": "",
"function": "",
"file": "/Applications/MAMP/htdocs/GTAB/what2days/api/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php",
"line": 150,
"args": []
}
It means nothing to me so I just made a var_export of $shardsStatistics variable and I get that:
array (
'total' => 6,
'successful' => 5,
'failed' => 1,
'failures' =>
array (
0 =>
array (
'index' => '.marvel-2014.09.16',
'shard' => 0,
'status' => 400,
'reason' => 'SearchParseException[[.marvel-2014.09.16][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"query":{"filtered":{"query":{"bool":{"must":[{"term":{"online":{"value":1}}}]}},"filter":{"bool":{"must":[{"geo_distance":{"distance":"100mi","location.latlon":{"lat":48.891773,"lon":2.3379156}}}]}}}}}},"size":"100"}]]]; nested: QueryParsingException[[.marvel-2014.09.16] failed to find geo_point field [location.latlon]]; ',
),
),
)
The error finish by " failed to find geo_point field [location.latlon]] ". I don't know why it doesn't work because when i check the _mapping the geo_point exists and i didn't make a mistake with the name of the property.
location: {
properties: {
latitude: {
type: "float",
store: true
},
latlon: {
type: "geo_point",
store: true,
lat_lon: true
},
longitude: {
type: "float",
store: true
}
}
},
And this is the way i set fos_elastica
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
search:
finder: ~
types:
mytype:
mappings:
title:
type: string
online:
type: integer
information: ~
location:
type: object
properties:
longitude:
type: float
latlon:
type: geo_point
lat_lon: true
boost: 10
persistence:
driver: orm
model: API\Rest\v1\MyBundle\Entity\MyEntity
provider: ~
listener: ~
finder: ~
repository: API\Rest\v1\MyBundle\Repository\MyRepository
When i make a kopf request with the query value (see following query) retrieved by $query->getQuery() i get a correct result.
{
"query": {
"filtered": {
"query": {
"bool": {
"must": [
{
"term": {
"online": {
"value": 1
}
}
}
]
}
},
"filter": {
"bool": {
"must": [
{
"geo_distance": {
"distance": "1mi",
"location.latlon": {
"lat": 48.891773,
"lon": 2.3379156
}
}
}
]
}
}
}
}
}
I don't know what to do. I was on 3.0.*#alpha version and now I'm trying the dev-master. I hope someone will help me find what goes wrong.
When I make a var_export in the method getData from Elastica/Response.php I have the failure I explained earlier and I also have 1 hit (the one Iwant to get).
I finally found the solution.
I had to add an index_name and tell \Elastica\Search to addIndex('new_index') and addType('specific type')
I thought the search will automatically get the correct index because I was using a specific repository but I was wrong.

Related objects in Freebase

In Freebase API, I want to fetch related objects to an object in Freebase. For example:
When I type in "Michael Jordan" (http://www.freebase.com/m/054c1) it should return "Chicago Bull's" (http://www.freebase.com/m/0jm74).
I went over https://developers.google.com/freebase/v1/search-cookbook but couldn't come up with a filter operand.
Any ideas?
I don't know which API you are using, but if you were to use the Freebase Search API, you would get the mid of the entity, then plug that back in to another search appropriate to that entity. The code below (in Javascript w/ jQuery) limits the input possibilities to a field where Mr.Jordan is present, then plugs it into a property found on basketball players: former teams.
$(function()
{
$("#myInput").suggest().bind("fb-select", function(e, data)
{
var topic_service = 'https://wwwlgoogleapis.com/freebase/v1/topic';
var params = {
'filter' : '(all type:/sports/sports_award_winner)'
};
$.getJSON(topic_service + data.id + '?callback=?', params, function(topic)
{
var teams = data.property['/basketball/basketball_player/former_teams']['values'];
for ( var i = 0; i < teams.length; i++)
{
alert(teams[i]);
}
})
})
});
You could do this without limiting the search, for more general types, but then you would have to do a query for what properties were held by that entity and then use that as a filter to get the data you were after.
On the other hand...
If you don't know that Jordan plays basketball, or what the properties of a basketball player are, you could call for the id of the links, find the properties of those links, then query for those properties on those links:
{
"mid": "/en/michael_jordan",
"type": [{
"id":null,
"properties": [{
"id":null,
"links": [{
"source": {
"id": "/en/michael_jordan"
},
"target": {
"id": null,
"optional": true,
},
"optional": true,
"target_value": null
}],
"master_property": {
"optional": true,
"links": [{
"source": {
"id": null
},
"target": {
"id": "/en/michael_jordan"
}
}]
}
}]
}
--This code is taken from the slide pack of an I/O talk given by Jamie Taylor in 2011.

Resources