|
While you're at it, you might also want to look into how it decides to capitalize random words for no reason.
|
|
|
|
|
I think the answer is "remove Cortana" ...
|
|
|
|
|
I have been examining Neo4j's implementation (Java engine, .NET/C# driver available). I have to control my knee-jerk "oohh ... alien" prejudice against Java technology.
The free book "Graph Databases," by Neo4j principals Robinson, et. al., published by O'Reilly, is an excellent overview of gdb's in general as well as Neo4j implementation features: download here [^].
So far all of the graph db's I've looked at implement connections (edges, links) between object (vertices, nodes) as one-way, which interests me since I am interested in modeling reciprocal relationships; the C# prototype I implemented for fun is based on two-way connections with each direction having a "strength," and dynamic interacting functions used, so ... when one direction changes strength ... the other direction's strength is modified (of course, two-way reciprocity demands preventing runaway recursion).
Neo4j defines Properties as "first class" objects, and they can be attached to either nodes, or connections: I really like that.
Here's an example, in Neo4j's query language, Cypher, that selects friends of friends of a selected person who are not immediate first-level friends of the person:
var people = new List<string[]>
{
new[] {"Jim", "Mike"}, new[] {"Jim", "Billy"}, new[] {"Anna"Neo4j, "Jim"},
new[] {"Anna", "Mike"}, new[] {"Sally", "Anna"}, new[] {"Joe", "Sally"},
new[] {"Joe", "Bob"}, new[] {"Bob", "Sally"}
}; Cypher code executed by Neo4j engine:
MATCH
(person:Person)-[:KNOWS]-(friend:Person)-[:KNOWS]-
(foaf:Person)
WHERE
person.name = "Joe"
AND NOT (person)-[:KNOWS]-(foaf)
RETURN
foaf You can see this code in a complete C# example here: [^].
Well, I find the Cypher syntax very weird, but, I never completed SQL potty-training I sat down and toyed with what I would do using Linq (which I am sure can be improved) to handle such a query, came up with this:
List<(string p1Name, string p2Name)> people = new List<(string, string)>
{
("Jim", "Mike"), ("Jim", "Billy"), ("Jim", "Jonas"), ("Anna", "Jim"),
("Anna", "Mike"), ("Sally", "Anna"), ("Joe", "Sally"),
("Joe", "Bob"), ("Bob", "Sally")
};
var friendsByPerson = people
.GroupBy(p =>
p.p1Name).ToDictionary(grp =>
grp.Key, grp =>
grp.Select(g =>
g.p2Name));
var friendsOfJoe = friendsByPerson["Joe"];
var friendsOfFriendsofJoe = friendsOfJoe
.SelectMany(name1 =>
friendsByPerson[name1].Where(name2 =>
!friendsOfJoe.Contains(name2))); If I were as smart as our local code witch, I might try to create a converter for C# <=> Cypher
If you care to share your experiences, or interest in graph db's, I am ready to eat your live coals of wisdom with สี่หูห้าตา "four eyes and five ears" [^]
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
modified 10-Feb-20 1:23am.
|
|
|
|
|
Gosh that syntax is weird.
And I'm not really smart so much as stubborn and determined, but that can be our secret.
Real programmers use butterflies
|
|
|
|
|
You should probably feel at home with Graph databases, since the thinking behind them are quite similar to your parsers.
Actually, it should be quite possible to create a database covering all aspects of for example regular expressions. Add a regex into the db and test a string using a query.
Note that I say possible, I don't necessarily think it's a good way to do it.
|
|
|
|
|
BillWoodruff wrote: I am interested in modeling reciprocal relationships
Trust me, one sided relationships are way better.
"It is easy to decipher extraterrestrial signals after deciphering Javascript and VB6 themselves.", ISanti[ ^]
|
|
|
|
|
lw@zi wrote: Trust me, one sided relationships are way better. Oh yeah, I'll trust you on that one !
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
It reminds me of PROLOG; when I was still a student we modelized the relationships between all Greek gods using it.
"Five fruits and vegetables a day? What a joke!
Personally, after the third watermelon, I'm full."
|
|
|
|
|
Greek Gods:
wonderful source site: [^]
an example of Neo4j indexing for Greek gods: [^]
Neo4j and D3js generated display of Greek Gods (German): [^]
a source db: [^]
graph using SAP-HANA: [^]
many happy theogonies to you
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
It seems Greek mythology is the 'Hello World!' equivalent to graph databases
"Five fruits and vegetables a day? What a joke!
Personally, after the third watermelon, I'm full."
|
|
|
|
|
There's a Youtube channel called Computerphile that has done a few videos on graph theory and the kind of problems it is used to solve. Might be worth hunting some down if you want to apply this to a real-world problem, as I find having an actual thing to solve is the best way to getting to learn a new technology.
|
|
|
|
|
Don't forget about relationship direction when working with graph DBs. Your Cypher query is bi-directional but the LINQ query is uni-directional. I really like Cypher and neo4j but haven't had much reason to use a graph DB recently Fun stuff though.
|
|
|
|
|
Jon McKee wrote: Don't forget about relationship direction Hi, Jon,
"Directionality" is an issue I raise explicitly in my post: don't forget that
Neo4j edges/vertices/connections are one-way. I see nothing in the Cypher query that suggests "Your Cypher query is bi-directional:" it's just a compound/chained query.
cheers, Bill
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
What I was alluding to was that no direction for the relationship is specified in your Cypher query. This means that outgoing and incoming relationships will be searched in the match. So for example:
CREATE (p1:Person)-[:KNOWS]->(p2:Person)
//Matches both p1 and p2
MATCH (p:Person)-[:KNOWS]-(:Person)
RETURN p
//Matches only p1
MATCH (p:Person)-[:KNOWS]->(:Person)
RETURN p
Un-directed was probably a better word to use than bi-directional. My bad. Since it's common to think of directed relationships as p2 "not knowing about" p1 since you can't traverse to p1 directly from p2, I figured I'd point out this little nuance of matching in case you weren't aware. The LINQ example would only match p1 so I thought maybe there was some misunderstanding.
|
|
|
|
|
Thanks Jon, for the clarification: I still can't see any differences between my translation of the Cypher into C# ... both are really two queries; I didn't chain the C# queries because I wanted to make the code more explicit for display here.
I think I see your point about bi-directional: the second query is looking for connections to Joe.
My apologies for being dense
cheers, Bill
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
If you start with Jim, your C# will throw an exception.
You could try:
var friendsOfFriendsofJoe = friendsOfJoe
.SelectMany(name => friendsByPerson.TryGetValue(name, out var myFriends) ? myFriends : Enumerable.Empty<string>())
.Except(friendsOfJoe)
.Where(name => name != "Joe"); Or you could go for the (only slightly brain-melting) functional option:
static class GraphExtensions
{
public static IReadOnlyDictionary<string, IEnumerable<string>> FriendsByPerson(this IEnumerable<(string n1, string n2)> source)
{
return source.GroupBy(p => p.n1).ToDictionary(g => g.Key, g => g.Select(p => p.n2));
}
public static Func<string, IEnumerable<string>> FriendsOfFriends(this IReadOnlyDictionary<string, IEnumerable<string>> friendsByPerson)
{
return name =>
{
if (!friendsByPerson.TryGetValue(name, out var friends))
{
return Enumerable.Empty<string>();
}
return friends
.SelectMany(f => friendsByPerson.TryGetValue(f, out var foaf) ? foaf : Enumerable.Empty<string>())
.Except(friends)
.Where(f => f != name);
};
}
}
...
Func<string, IEnumerable<string>> foafByPerson = people.FriendsByPerson().FriendsOfFriends();
foreach (string foaf in foafByPerson("Anna"))
{
Console.WriteLine(foaf);
} Obviously this assumes the connections are one-way - Jim knows Mike, but Mike doesn't know Jim. If Cypher / Neo4J assumes bi-directional connections, the code would get slightly more complicated:
public static IReadOnlyDictionary<string, IEnumerable<string>> FriendsByPerson(this IEnumerable<(string n1, string n2)> source)
{
return source
.Concat(source.Select(p => (n1: p.n2, n2: p.n1)))
.GroupBy(p => p.n1)
.ToDictionary(group => group.Key, group => group.Select(p => p.n2));
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Wow ! Thanks ... I will, as ever, study your keen insights and code
I really like functions that return functions !
cheers, Bill
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
|
Quote: think the game designers should bear some responsibility here as well...
Not disagreeing, but...
Quote: Katie Phillips' daughter reset security settings to accept her own fingerprint to make purchases I believe some one else has more responsibility.
Assuming this simply isn't just the parents bullshitting.
|
|
|
|
|
Don't get me wrong - the daughter is the primary culprit, and her mother deserves blame as well.
But Roblox is designed for kids, and it's at best unethical to allow them to do that. If gambling is "restricted" with gambling companies required to warn people if they are spending too much too quickly (and they are in the UK at least though it's as useful as a chocolate teapot) then allowing kids to generate that kind of debt is a disgusting practice IMO.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I was actually referring to a certain fruit company in this case.
Having so bad security that the daughter could change the fingerprint for appstore is remarkable, imao.
On that other system I have Family link installed. Any time my kids try to install something that costs money, I have to ok it. On my own phone.
I also get the possibility to limit the time spent on these gadgets, and I can easily block apps I don't agree with. On distance.
The kids learn quickly and don't click anything that's an In app purchase.
|
|
|
|
|
You don't mean ... iPurchases iGive iPercentage iTo iCompany iSo iThey iDon't iCare ... iSurely iNot!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
OriginalGriff wrote: You don't mean ...
Actually...
|
|
|
|
|
But ...
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Jörgen Andersson wrote: Having so bad security that the daughter could change the fingerprint for appstore is remarkable, imao. I didn't think it was possible. Any changes to verification methods/details require entry of the password.
There may be more to this than Mum is telling.
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|