How to include "citation" attributes/properties in graphs? - graph

I am creating a domain-specific model which includes entities that have attributes whose original source or citation needs to be defined.
In graql for example:
define
"country" sub entity
has population;
"evidence" sub attribute datatype string;
"population" sub attribute datatype string
has evidence;
This seems to define an attribute of an attribute, and conceptually seems to make the meaning of the attribute dependent on a certain context, which is arguably better modelled as annotated "fact" entities with relationships to other entities.
What is the simplest way to model attributes like these without increasing complexity of the model?

Attributes of attributes
Attributes of attributes don't necessarily work as you might expect. It's important to remember that in Grakn there will be only one node in the graph for an attribute of a particular type with a particular value.
That is to say an attribute of type population value sixty million will only occur once in the knowledge graph.
If we change your schema slightly to add names for countries (also there's no need for single quotes around types):
define
country sub entity
has population,
has name;
name sub attribute datatype string;
evidence sub attribute datatype string;
population sub attribute datatype string
has evidence;
Then add two countries to the knowledge graph:
insert $uk isa country, has name 'UK', has population $p; $p 'sixty million' has evidence 'journal';
insert $fr isa country, has name 'France', has population $p; $p 'sixty million' has evidence 'wikipedia';
commit;
What we can see if we visualise it is that we can't tell the source of the population for each country separately, because both of the countries and both of the pieces of evidence are connected to the same population instance.
(Visualised in Grakn Workbase Visualiser)
Attributes of attributes make sense in a case like:
attribute phrase value Hi there! owning an attribute language value English. That is, the language attribute is referring to the value of the phrase attribute.
This means that if you want to record the source of an attribute you'll need to do things differently. I suggest three possible options. Note, that for each of the following three ideas population shouldn't own evidence for the reason mentioned. In the schema above population sub attribute datatype string has evidence; should become population sub attribute datatype string;
1. Implicit relationships
Under the hood Grakn has implicit relationships to implement attribute ownership, always autogenerated and prefixed with #has-, for example #has-population. We can attach attributes to these implicit relationships!
First delete the instances we inserted above (this will delete all entities and attributes in the graph, beware!):
match $x isa entity; $y isa attribute; delete $x, $y;
Then define that the implicit population attribute can own evidence and add examples:
define #has-population has evidence;
insert $uk isa country, has name 'UK', has population $p via $r; $p 'sixty million'; $r has evidence 'journal';
insert $fr isa country, has name 'France', has population $p via $r; $p 'sixty million'; $r has evidence 'wikipedia';
Now we're able to disambiguate the evidence for the UK's population from the evidence for France's population. We can query for this:
match $c isa country, has name $n, has population $p via $r;
$p 'sixty million'; $r has evidence $e; get $n, $e;
Result:
{$n val "France" isa name; $e val "wikipedia" isa evidence;}
{$n val "UK" isa name; $e val "journal" isa evidence;}
2. Relationships to implicit relationship
If the evidence is more complex than a single attribute, then it may be better modelled as a relationship, in which #has-population plays a role.
define
information-sourcing sub relationship,
relates sourced-information,
relates information-source;
#has-population plays sourced-information;
publication sub entity,
plays information-source;
insert $uk isa country, has name 'UK', has population $p via $r; $p 'sixty million'; $pub isa publication; $i(sourced-information: $r, information-source: $pub) isa information-sourcing;
insert $uk isa country, has name 'France', has population $p via $r; $p 'sixty million'; $pub isa publication; $i(sourced-information: $r, information-source: $pub) isa information-sourcing;
3. A normal relationship
Finally, you could create a relationship that links the population, country, and evidence, that avoids using implicit relationships if these seem too complex.
Conclusion
Which method to use depends on the domain you're modelling. In answer to your question, the first method adds the fewest additional elements to the schema.

Related

I don't know how to verify if a parameter exists in the funcion or procedure

Design a table named "customs agencies" with the following fields: name, address, patent number, id_ customs agent. Where customs agent is another table with name and seniority.
Create a function or procedure that allows inserting new agencies and being able to edit an agency giving the ID of the customs agency.
I don't know how to do this: If id exists in parameter we do an update, else we insert new agencies.
Suppose parameter's name is PAR_ID; then you'd
create or replace procedure p_agency (par_id in agency.id%type,
par_name in agency.name%type
)
is
begin
if par_id is null then
insert into agency (id, name) values (par_id, par_name);
else
update agency set name = par_name
where id = par_id;
end if;
end;
If you wonder where are other columns - well, I'll leave that piece of homework to you.

typedb.common.exception.TypeDBClientException: [QRY16] Invalid Query Pattern

When i am trying to fetch count. getting this below error
``[QRY16] Invalid Query Pattern: The pattern '{{ $xy isa taggedwith; $xy ($x, $y); $x has $_0; $x isa Person; $y isa Employer; $_0 = "ab333a1a-0688-4d70-a9da-32b095a69223"; $_0 isa unique_id; }}' can never be satisfied the current schema, specifically due to '[{ $xy isa taggedwith; $xy ($x, $y); $x has $_0; $x isa Person; $y isa Employer; $_0 = "ab333a1a-0688-4d70-a9da-32b095a69223"; $_0 isa unique_id; }]'.
Please check server logs for the stack trace`.`
Actual Query i am using:
match $x isa Person; {$x id ab333a1a-0688-4d70-a9da-32b095a69223;}; $xy ($x, $y) isa taggedwith; $y isa Employer; get $y; count;
I want to fetch count, without any issues.
This error indicates that you've written a query that is not semantically valid according to your schema. For example, it's possible that a Person or an Employer cannot be part of a taggedwith relation, which means this query will never find any results.
The best way to debug this error is to partition your query into smaller parts that are not invalid, then add the pieces back one by one until you find the part of the query that causes the error.
Also, it looks like the id keyword should not be valid. There is a TypeQL keyword (in version 2.8.0) called iid but it requires a hex input, such as $x iid 0x123.... If id is an attribute you have created on Person, you'll want to use $x has id "ab333a1a-0688-4d70-a9da-32b095a69223" as a string attribute.
Hope this helps!

using xquery to count employees in department (same lvl tag)

I have a xml file like this:
<employees>
<emp_num>
<department>1</department>
<salary>1000</salary>
</emp_mum>
<emp_num>
<department>1</department>
<salary>2000</salary>
</emp_mum>
</employees>
I want to know the number of employees per department ordered by the average salary of the department.
My main problem to do this is that "department" and "salary" are at the same level and I don't know how to use FLWOR in this situation.
Try
for $emp in //emp_num
group by $d := $emp/department
order by avg($emp/salary)
return count($emp)

cypher: how to return distinct relationship types?

How to return the distinct relationship types from all paths in cypher?
Example query:
MATCH p=(a:Philosopher)-[*]->(b:SchoolType)
RETURN DISTINCT EXTRACT( r in RELATIONSHIPS(p)| type(r) ) as RelationshipTypes
This returns a collection for each path p.
I would like to return a single collection contain the distinct relationship types across all collections.
Here is a link to a graph gist to run the query-
http://gist.neo4j.org/?7851642
You might first collect all relationships on the matched path to a collection "allr", and then get the collection of distinct type(r) from the collection of all relationships,
MATCH p=(a:Philosopher)-[rel*]->(b:SchoolType)
WITH collect(rel) AS allr
RETURN Reduce(allDistR =[], rcol IN allr |
reduce(distR = allDistR, r IN rcol |
distR + CASE WHEN type(r) IN distR THEN [] ELSE type(r) END
)
)
Note, each element 'rcol' in the collection "allr" is in turn a collection of relationships on each matched path.

Entity having two entities of the same type

I'm programming a small game and a database representing Players and Matches.
A player has a name, a player ID and a rank.
A match has an ID, and two players.
Player
* id (bigint)
name (string)
playerID (string)
rank (integer)
Match
* id (bigint)
matchID (string)
playerOne (Player)
playerTwo (Player)
I would like to have a "matches" relationship in a Player, but how do I have an entity having two entities of same type and what type relationship should I use?
I tried a one-to-one relationship, but the UNIQUE condition it created is a problem.
You need a many-to-many relationship. This is usually done with a "middle" or "link" table. In this example the PlayedMatch table is the link table.
This is effectively a single many-to-many relationship between Player and Match. However it is represented by 2 one-to-many relationships :
Player [1] --> [n] PlayedMatch
Match [1] --> [n] PlayedMatch
Player
Id
Name
Rank
Match
Id
PlayedMatch
Id
MatchId
Player1Id
Player2Id
I see you've got some string properties named PlayerId and MatchId. Avoid these names if you can because they are usually used for foreign key relationships.
You would probably want some more properties in the PlayedMatch table like WinnerId (linking to Player).
A SQL query on the above would look something like this:
SELECT
*
FROM
PlayedMatch pm
INNER JOIN Player p1 ON pm.Player1Id = p1.Id
INNER JOIN Player p2 ON pm.Player2Id = p2.Id
INNER JOIN Match m ON pm.MatchId = m.Id
If you want to easily find all matches per player you will need to use a ManyToMany relationship. The following is a simplified snippet of what the classes would look like.
class Player {
/**
* #ORM\ManyToMany(targetEntity="Match", mappedBy="players")
*/
protected $matches;
}
class Match {
/**
* #ORM\ManyToMany(targetEntity="Player", inversedBy="matches")
*/
protected $players;
}
Then you run the following command from the root directory:
php app/console doctrine:generate:entities Your/AwesomeBundle/Entity
And you will be able to use methods such as:
Match::getPlayers()
Match::addPlayer()
Player::addMatch() // probably will have an 'e' at the end of the word match
Player::getMatches() // which is the one that will give you all matches of a user
You will need to restrict the number of players per match in your code.

Resources