-
Notifications
You must be signed in to change notification settings - Fork 12
/
pole.neo4j-browser-guide
905 lines (746 loc) · 37.7 KB
/
pole.neo4j-browser-guide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
<style type="text/css" media="screen">
/*
.nodes-image {
margin:-100;
}
*/
@import url("//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css");
.imageblock .content img, .image img {max-width: 100%;}
.deck h3, .deck h4 {display: block !important;margin-bottom:8px;margin-top:5px;}
.listingblock {margin:8px;}
.pull-bottom {position:relative;bottom:1em;}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
.admonitionblock.note.speaker { display:none; }
</style>
<style type="text/css" media="screen">
/* #editor.maximize-editor .CodeMirror-code { font-size:24px; line-height:26px; } */
</style>
<article class="guide" ng-controller="AdLibDataController">
<carousel class="deck container-fluid">
<!--slide class="row-fluid">
<div class="col-sm-3">
<h3>POLE Data Model Guide</h3>
<p class="lead">Information</p>
<!dl>
</dl>
</div>
<div class="col-sm-9">
<figure>
<img style="width:300px" src=""/>
</figure>
</div>
</slide-->
<h4>POLE Data Model Guide</h4>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>POLE Model Overview</h3>
<br/>
<div>
<div class="imageblock">
<div class="content">
<img src="https://guides.neo4j.com/sandbox/pole/img/pole_model_visual.jpeg" alt="pole model visual">
</div>
</div>
<div class="paragraph">
<p>This guide will demonstrate how Neo4j can be used with a POLE data model in the context of police and child protection investigations.</p>
</div>
<div class="paragraph">
<p>The POLE data model focuses on four basic types of entities and the relationships between them: <strong>P</strong>ersons, <strong>O</strong>bjects, <strong>L</strong>ocations, and <strong>E</strong>vents.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>POLE Model Use Cases</h3>
<br/>
<div>
<div class="paragraph">
<p>The POLE data model is a standard approach used in policing, investigative, and security use cases. It can also, however, be applied in other areas. Typical POLE use cases include:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Policing</p>
</li>
<li>
<p>Counter Terrorism</p>
</li>
<li>
<p>Border Control / Immigration</p>
</li>
<li>
<p>Child Protection / Social Services</p>
</li>
<li>
<p>Missing Persons</p>
</li>
<li>
<p>Offender Rehabilitation</p>
</li>
<li>
<p>Insurance Fraud Investigations</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Graphs are a perfect fit for use cases like these, where it is important to be able to work with highly connected data in real time. Using a real-time graph helps investigators to be <em>proactive</em> and prevent crime or other incidents, rather than simply being reactive after an incident has occurred. A POLE graph can also be used to generate insights into patterns of behaviour and incidents, which can inform new approaches and enable more targeted use of limited resources.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>About the data for this demo</h3>
<br/>
<div>
<div class="paragraph">
<p>Crime data for this demo was downloaded from public sources (<a href="http://data.gov.uk" class="bare">http://data.gov.uk</a>), and is freely provided for download with locations defined to the block or street level and crimes defined by month only (i.e. no day or timestamp). This public crime data does not include any sort of information about persons related to crimes, not even as anonymised tokens - it supplies only crime and location data, or in other words only the 'L' and 'E' for the POLE model. This demo uses street crime data for Greater Manchester, UK from August 2017.</p>
</div>
<div class="paragraph">
<p>Unique crime IDs, longitude, latitude, crime type, street/locale name, and last outcome values were taken from the public street crime data files. UK postcodes were retrieved from a public API using Longitude and Latitude, and randomly generated or curated data was used for other entities in the database (vehicles, officers, people, phone numbers, phone calls, emails, day of the month, etc.).</p>
</div>
<div class="paragraph">
<p><em>All scenarios and persons portrayed in this demo are fictitious. Any similarity to real persons or events is coincidental and unintentional.</em></p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>General Queries</h3>
<br/>
<div>
<h4>Schema</h4>
<div class="paragraph">
<p>Review the metagraph, and see the types of nodes and relationships we’re going to be working with.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->call db.schema.visualization()<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>Notice the different ways that Persons can be related to each other. There is a general 'KNOWS' relationship, as well as more specific relationship types: FAMILY_REL (related to), KNOWS_LW (lives with), KNOWS_PHONE (has a related phone call), and KNOWS_SN (social network).</p>
</div>
<div class="paragraph">
<p>Notice also that Location is associated to both Postcode and Area. In the UK, Postcodes follow a format which splits the postcode into two sections - for example, M1 1AA. In this example, 'M1 1AA' is the Postcode, and 'M1' is the area. This allows us to group locations in different ways, and build query paths that are either more specific (like Postcode, which is typically limited to a street or a few blocks) or more general (like Area, which could cover a town or city neighbourhood).</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>General Queries</h3>
<br/>
<div>
<h4>Crime totals</h4>
<div class="paragraph">
<p>Let’s have a look at the types of crimes in the graph, and the number of times each occurred:</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (c:Crime)
RETURN c.type AS crime_type, count(c) AS total
ORDER BY count(c) DESC<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>You should see that 'Violence and sexual offences' was the highest category of crimes for the month, with weapons offences being the category with the lowest count.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>General Queries</h3>
<br/>
<div>
<h4>Top locations for crimes</h4>
<div class="paragraph">
<p>Let’s also look at the top locations in the graph where crimes have been recorded:</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (l:Location)<-[:OCCURRED_AT]-(:Crime)
RETURN l.address AS address, l.postcode AS postcode, count(l) AS total
ORDER BY count(l) DESC
LIMIT 15<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>You should see several obvious public places and institutions with high numbers of crime associated - Piccadilly (the area near the main rail station in Manchester), a Shopping Area (and a nearby Prison), etc. There are some residential-looking addresses towards the bottom of the list with pretty high numbers (i.e. 35 crimes at both 182 Waterson Avenue and 43 Walker’s Croft).</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>General Queries</h3>
<br/>
<div>
<h4>Crimes near a particular address</h4>
<div class="paragraph">
<p>The popular UK television drama 'Coronation Street' is set in a fictional Manchester-area neighbourhood. There’s a Coronation Street address in the graph (1 Coronation Street, home of the Barlow family in the show). Using the longitude and latitude properties in our Location nodes we can do a distance-based search to find crimes that are within 500 metres of this address.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (l:Location {address: '1 Coronation Street', postcode: 'M5 3RW'})
WITH point(l) AS corrie
MATCH (x:Location)-[:HAS_POSTCODE]->(p:PostCode),
(x)<-[:OCCURRED_AT]-(c:Crime)
WITH x, p, c, point.distance(point(x), corrie) AS distance
WHERE distance < 500
RETURN x.address AS address, p.code AS postcode, count(c) AS crime_total, collect(distinct(c.type)) AS crime_type, distance
ORDER BY distance
LIMIT 10<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>General Queries</h3>
<br/>
<div>
<h4>Crimes investigated by Inspector Morse</h4>
<div class="paragraph">
<p>Another popular UK television drama is 'Inspector Morse'. There’s also an Inspector Morse in our graph - let’s see what Crimes he is investigating.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (o:Officer {rank: 'Chief Inspector', surname: 'Morse'})<-[i:INVESTIGATED_BY]-(c:Crime)
RETURN *<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>You should see quite a number of Crime nodes connected by the INVESTIGATED_BY relationship to the Inspector Morse node. Take a few minutes to click on some of them to expand the graph and see what other nodes are related to some of these Crimes.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Crime Investigation</h3>
<br/>
<div>
<h4>Crimes under investigation by Officer Larive</h4>
<div class="paragraph">
<p>Let’s say we are interested in the crimes that are under investigation by Police Constable Devy Larive (Badge Number 26-5234182).</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (c:Crime {last_outcome: 'Under investigation'})-[i:INVESTIGATED_BY]->(o:Officer {badge_no: '26-5234182', surname: 'Larive'})
return *<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>We can see Police Constable Larive is investigating a number of crimes at the moment. In particular we can see that PC Larive is investigating three Drugs Crimes. Double clicking on these three Drugs crimes shows us:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Two of them are for the charge Possession of Cannabis with Intent To Supply, occurring at the same address and having the same related person (Jack Powell). These crimes have evidence attached to them - large amounts of currency, some cannabis, and an electronic scale (all indicators of cannabis sale/distribution).</p>
</li>
<li>
<p>The third Crime is for the charge 'Production of Cannabis with Intent To Supply', related to Raymond Walker. This crime also has two Evidence nodes attached.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>We could click on these nodes and manually explore the graph to get more information, but instead let’s write some queries which can help us investigate further.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Crime Investigation</h3>
<br/>
<div>
<h4>Shortest path between persons related to crimes</h4>
<div class="paragraph">
<p>Let’s see if the two Persons - Jack Powell and Raymond Walker - associated with these three Drugs Crimes are somehow connected in the graph. We’ll look for all of the shortest paths between them of 3 or fewer hops along all types of 'KNOWS' relationships. We can ignore the direction of the relationships in this query, as we’re not interested in which direction they point.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (c:Crime {last_outcome: 'Under investigation', type: 'Drugs'})-[:INVESTIGATED_BY]->(:Officer {badge_no: '26-5234182'}),
(c)<-[:PARTY_TO]-(p:Person)
WITH COLLECT(p) AS persons
UNWIND persons AS p1
UNWIND persons AS p2
WITH * WHERE id(p1) < id(p2)
MATCH path = allshortestpaths((p1)-[:KNOWS|KNOWS_LW|KNOWS_SN|FAMILY_REL|KNOWS_PHONE*..3]-(p2))
RETURN path<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>It turns out they are part of what looks like a social group. Two of Raymond’s family relations (his father Phillip and sister Kathleen) know Alan Ward, who is the brother of Jack Powell. Raymond’s father Phillip also lives with Jack’s father Brian. Knowing that Raymond is under investigation for production of cannabis, that Jack is under investigation for two separate charges of possession of cannabis with intent to supply, and that they seem to be part of a social group we can speculate it’s possible that they know each other and that Jack is getting his cannabis from Raymond.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Crime Investigation</h3>
<br/>
<div>
<h4>Other related people associated with drugs crimes</h4>
<div class="paragraph">
<p>To build an even stronger case let’s look at the social networks of Jack Powell and Raymond Walker, and see if anyone else within 3 hops of them along 'KNOWS' relationships is also related to a Drugs Crime.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH path = (:Officer {badge_no: '26-5234182'})<-[:INVESTIGATED_BY]-(:Crime {type: 'Drugs'})<-[:PARTY_TO]-(:Person)-[:KNOWS*..3]-(:Person)-[:PARTY_TO]->(:Crime {type: 'Drugs'})
RETURN path<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>This query reveals an interesting and somewhat dense social network, including family relations and people who live with one another. Reviewing the graph we can see:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Jack is also under investigation (by different officers) for two other Drugs Crimes. PC Larive might want to try to get information on those cases, too.</p>
</li>
<li>
<p>Jack’s father Brian is related to three Drugs Crimes - each time charged with Possession of Cannabis.</p>
</li>
<li>
<p>Within 3 hops of both Raymond and Jack is Diana Murray, who is related to three Drugs Crimes - one of simple possession and two with intent to supply.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>It’s possible that Raymond has been growing cannabis and supplying it to Jack and Diana, both of whom are then dealing it onward. Take a few minutes to explore the relationships and understand how Raymond, Jack, and Diana may know each other.</p>
</div>
<div class="paragraph">
<p>We might also be able to infer some additional relationships in this graph:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Given that Kathleen and Phillip both know Alan, it is possible that Raymond knows Alan - even though that’s not explicit in the graph?</p>
</li>
<li>
<p>Similarly, given that Alan and Brian know Phillip, is likely that Jack knows Phillip as well?</p>
</li>
</ul>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<div class="paragraph">
<p>Now we can explore a series of queries to simulate research on 'vulnerable' or 'at risk' individuals in the graph. This might be especially important in a social services or child protection use case. Here we have defined 'vulnerable person' as someone who is not themselves associated to a crime, but who knows many people who are. Run the query below to generate a list of the Top 5 most vulnerable people in the graph.</p>
</div>
<h4>Top 5 vulnerable people in the graph</h4>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p:Person)-[:KNOWS]-(friend)-[:PARTY_TO]->(:Crime)
WHERE NOT (p:Person)-[:PARTY_TO]->(:Crime)
RETURN p.name AS name, p.surname AS surname, p.nhs_no AS id, count(distinct friend) AS dangerousFriends
ORDER BY dangerousFriends DESC
LIMIT 5<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>We will be referring to this list of Vulnerable people throughout the next few steps, so you may want to keep the results handy (try using the tack icon to pin them to the top).</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Friends of Friends</h4>
<div class="paragraph">
<p>Using Cypher it’s then very easy to explore the graph out through a wider social circle. A small change to the query allows us to see not only friends of individuals who are associated with crimes, but also 'friends of friends' who are associated with crimes as well.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p:Person)-[:KNOWS*1..2]-(friend)-[:PARTY_TO]->(:Crime)
WHERE NOT (p:Person)-[:PARTY_TO]->(:Crime)
RETURN p.name AS name, p.surname AS surname, p.nhs_no AS id, count(distinct friend) AS dangerousFriends
ORDER BY dangerousFriends DESC
LIMIT 5<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>Try modifying the query to look at 'friends of friends of friends' (3 'KNOWS' relationships out) and see how that changes the results.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Exploring a Vulnerable Person’s graph</h4>
<div class="paragraph">
<p>Let’s explore the graph for the top result from our original Vulnerable Persons results (which, hopefully, you’ve pinned in a previous step).</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH path = (:Location)<-[:CURRENT_ADDRESS]-(:Person {nhs_no: '804-54-6976', surname: 'Freeman'})-[:KNOWS]-(:Person)-[:PARTY_TO]->(:Crime)
RETURN path<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>We can see that Anne Freeman has 8 dangerous friends. Using her ID, this query shows us the graph of these friends, which we can navigate and explore.</p>
</div>
<div class="paragraph">
<p>You can also try updating this query to show 'friends of friends' or 'friends of friends of friends' like we did previously.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Looking for local Dangerous Friends</h4>
<div class="paragraph">
<p>Now that we’ve seen Anne Freeman’s social circle, it would be good to know whether any of her dangerous friends is actually local to her (in her area, or neighbourhood).</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (anne:Person {nhs_no: '804-54-6976', surname: 'Freeman'})-[k:KNOWS]-(friend)-[pt:PARTY_TO]->(c:Crime),
(anne)-[ca1:CURRENT_ADDRESS]->(aAddress)-[lia1:LOCATION_IN_AREA]->(area),
(friend)-[ca2:CURRENT_ADDRESS]->(fAddress)-[lia2:LOCATION_IN_AREA]->(area)
RETURN *<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>We can see it’s only her friend Craig, who she knows through social networks, that lives in the same Area (SK1) as Anne. Craig has been associated with two Public Order offences.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Looking for connections between Vulnerable Persons</h4>
<div class="paragraph">
<p>Going back to the list of vulnerable people, let’s see if any of them are connected. This query takes the results of the vulnerable people query and looks for paths of 'KNOWS' relationships that connect them.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p:Person)-[:KNOWS]-(friend)-[:PARTY_TO]->(:Crime)
WHERE NOT (p:Person)-[:PARTY_TO]->(:Crime)
WITH p, count(distinct friend) AS dangerousFriends
ORDER BY dangerousFriends DESC
LIMIT 5
WITH COLLECT (p) AS people
UNWIND people AS p1
UNWIND people AS p2
WITH * WHERE id(p1) <> id (p2)
MATCH path = shortestpath((p1)-[:KNOWS*]-(p2))
RETURN path<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>It turns out there are connections between them, of different lengths. There are actually multiple paths by which some of them are connected.</p>
</div>
<div class="paragraph">
<p>We’re finished now with the original list of vulnerable people and those results can be closed or unpinned.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Looking for Dangerous Family Friends</h4>
<div class="paragraph">
<p>We can now write another query looking for vulnerable or at risk individuals, but this time based on their family relationships rather than their direct social relationships. We’ll look for people who are not directly related to a crime, and neither is their relative, but their relative has dangerous friends.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p:Person)-[:FAMILY_REL]-(relative)-[:KNOWS]-(famFriend)-[:PARTY_TO]->(:Crime)
WHERE NOT (p:Person)-[:PARTY_TO]->(:Crime) AND
NOT (relative)-[:PARTY_TO]->(:Crime)
RETURN p.name AS name, p.surname AS surname, p.nhs_no AS id, count(DISTINCT famFriend) AS DangerousFamilyFriends
ORDER BY DangerousFamilyFriends DESC
LIMIT 5<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>You should see 5 people who have family members with dangerous friends.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Looking for Dangerous Family Friends</h4>
<div class="paragraph">
<p>The previous query returned a good set of at risk individuals. However, it’s probably not specific enough - it would be more interesting to see this list with an additional requirement that the vulnerable individuals live with their relative who has dangerous friends.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p:Person)-[:FAMILY_REL]-(relative)-[:KNOWS]-(famFriend)-[:PARTY_TO]->(:Crime),
(p)-[:CURRENT_ADDRESS]->(:Location)<-[:CURRENT_ADDRESS]-(relative)
WHERE NOT (p:Person)-[:PARTY_TO]->(:Crime) AND
NOT (relative)-[:PARTY_TO]->(:Crime)
RETURN p.name AS name, p.surname AS surname, p.nhs_no AS id, count(DISTINCT famFriend) AS DangerousFamilyFriends
ORDER BY DangerousFamilyFriends DESC
LIMIT 5<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>This version of the query returns only 2 people, but the one with the highest number of dangerous family friends (Kimberly Alexander) is the same as from the results of the previous query.</p>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Vulnerable Persons Investigation</h3>
<br/>
<div>
<h4>Exploring a Vulnerable Person’s graph</h4>
<div class="paragraph">
<p>We can view Kimberley’s graph, and see that Kimberly (age 12) lives with her mother Bonnie at 53 Ridge Grove. Bonnie has several friends who are related to a number of crimes of varying types. There’s a high chance that Kimberly is being exposed to these people, potentially putting her at risk.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH path = (relative:Person)-[:CURRENT_ADDRESS]->(:Location)<-[:CURRENT_ADDRESS]-(:Person {nhs_no: '548-59-5017', surname: 'Alexander'})-[:FAMILY_REL]-(relative)-[:KNOWS]-(:Person)-[:PARTY_TO]->(:Crime)
RETURN path<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Graph Algorithms</h3>
<br/>
<div>
<h4>Graph projection</h4>
<div class="paragraph">
<p>Lastly, we can have a look at a few graph algorithms and see how they can be applied to our use case.
Graph algorithms are executed on in-memory graph projections.
You have the option to project the whole stored graph or only a subset of the graph depending on your requirements.</p>
</div>
<div class="paragraph">
<p>Run the following query to project Person nodes and KNOWS relationships in the in-memory graph.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->CALL gds.graph.project('social',
'Person',
{KNOWS: {orientation:'UNDIRECTED'}})<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Triangle Count</h4>
<div class="paragraph">
<p>The triangle count algorithm returns 'triangles' of connected nodes - in this case, groups of three Persons where every node in the group 'KNOWS' the others ('A' knows 'B' knows 'C' knows 'A'). This is a common approach when analysing social graphs, where the incidence of such triangles is higher than it would be in a random data set/sample. This identifies communities or clusters of connectivity in graphs, and might be used in a policing context to identify gangs or other criminal/suspected groups.</p>
</div>
<div class="paragraph">
<p>Run the following query to identify Person nodes in our graph who are members of the highest number of triangles.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->CALL gds.triangleCount.stream('social')
YIELD nodeId, triangleCount as triangles
WITH gds.util.asNode(nodeId) AS node, triangles
RETURN node.name AS name, node.surname AS surname, node.nhs_no AS id, triangles
ORDER BY triangles DESC
LIMIT 10;<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Triangle Count</h4>
<div class="paragraph">
<p>We can take a look at the graph for one of the sets of triangles that was returned - Deborah Ford, who belongs to ten triangles.</p>
</div>
<div class="paragraph">
<p>We can see that Patricia Carr knows both Deborah Ford and Jonathan Hunt, and both Deborah and Jonathan know Peter Bryant, Harry Lopez, and Phillip Perry. We can might therefore infer that Patricia knows Peter, Harry, and Phillip as well.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH path = (p1:Person {nhs_no: '838-45-9343', surname: 'Ford'})-[:KNOWS]-(p2)-[:KNOWS]-(p3)-[:KNOWS]-(p1)
RETURN path<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Triangle Count on a Subgraph</h4>
<div class="paragraph">
<p>The previous query was interesting, but we ran it against the entire graph. We can use the same algorithm on a sub-graph - for instance, only people who associated with crimes. This returns a different set of triangles, consisting only of people associated with crimes who appear in communities/clusters.</p>
</div>
<div class="paragraph">
<p>Run the following query to project a subgraph that contains only people associated with crimes.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p0:Person)-[:PARTY_TO]->(:Crime)
WITH collect(DISTINCT id(p0)) as criminalPartyIds
MATCH (s:Person)-[r:KNOWS]->(t:Person)
WHERE (id(s) IN criminalPartyIds) AND (id(t) IN criminalPartyIds)
WITH gds.alpha.graph.project('crime-associates', s, t,
{sourceNodeLabels:labels(s), targetNodeLabels:labels(t)},
{relationshipType:type(r)}, {undirectedRelationshipTypes:[type(r)]}) AS g
RETURN g.graphName AS graph, g.nodeCount AS nodes, g.relationshipCount AS rels<!--/code--></pre>
</div>
</div>
<div class="paragraph">
<p>After you have projected the in-memory graph, you can run the triangle count of the crime associate subgraph by executing the following query.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->CALL gds.triangleCount.stream('crime-associates')
YIELD nodeId, triangleCount as triangles
WITH gds.util.asNode(nodeId) AS node, triangles
RETURN node.name AS name, node.surname AS surname, node.nhs_no AS id, triangles
ORDER BY triangles DESC
LIMIT 5;<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Triangle Count on a Subgraph</h4>
<div class="paragraph">
<p>Looking at the triangles associated to one of the top results from the previous query (Phillip Williamson) shows an interesting group of people who know each other, are related to each other, and/or live with each other. The names look familiar from our previous Drugs investigation - we have quite a group of potential criminals here. In addition to the Drugs Crimes there are a lot of Vehicle Crimes associated with this social group. Perhaps this is a gang which specialises in car theft. It’s interesting to note how the algorithms automatically turned up something we needed to specifically search for earlier (during our Drugs search we had specific Officer and Person starting nodes from our search).</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH (p1:Person {nhs_no: '337-28-4424', surname: 'Williamson'})-[k1:KNOWS]-(p2)-[k2:KNOWS]-(p3)-[k3:KNOWS]-(p1)
WITH *
MATCH (person)-[pt:PARTY_TO]->(crime) WHERE person IN[p1, p2, p3]
RETURN *<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Betweenness Centrality</h4>
<div class="paragraph">
<p>The betweenness algorithm measures centrality in the graph - a way of identifying the most important nodes in a graph. It does this by identifying nodes which sit on the shortest path between many other nodes and scoring them more highly. We can see the people here which are potentially important in the graph by using this measure - they sit on the shortest path between the most other people via the 'KNOWS' relationship (ignoring relationships direction, as it’s not very important here). Information and resources tend to flow along the shortest paths in a graph, so this is one good way of identifying central nodes or 'bridge' nodes between communities in the graph.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->CALL gds.betweenness.stream('social')
YIELD nodeId, score AS centrality
WITH gds.util.asNode(nodeId) AS node, centrality
RETURN node.name AS name, node.surname AS surname, node.nhs_no AS id, toInteger(centrality) AS score
ORDER BY centrality DESC
LIMIT 10;<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>Algorithms</h3>
<br/>
<div>
<h4>Betweenness Centrality</h4>
<div class="paragraph">
<p>We can explore the graph for the top result from the previous query (Annie Duncan) out to 3 levels and see how well connected she is. She does appear to sit between several clusters/communities at the edge of this graph. We get even more results if we look farther out than 3 hops, but the results would be harder to visualise and take longer to draw on the screen.</p>
</div>
<div class="listingblock">
<div class="content">
<pre mode="cypher" class="highlight pre-scrollable programlisting cm-s-neo code runnable standalone-example ng-binding" data-lang="cypher" lang="cypher"><!--code class="cypher language-cypher"-->MATCH path = (:Person {nhs_no: '863-96-9468', surname: 'Duncan'})-[:KNOWS*..3]-(:Person)
RETURN path<!--/code--></pre>
</div>
</div>
</div>
</div>
</slide>
<slide class="row-fluid">
<div class="col-sm-12">
<h3>End of the guide</h3>
<br/>
<div>
<div class="paragraph">
<p>This was a simplified demo, and a real POLE model populated with actual police data would be much more complicated and rich. However, this was a good way to explore some POLE data modelling and queries in a semi-real world way.</p>
</div>
<div class="paragraph">
<p>To make the demo easier to follow we used 'NHS Number' as simulated unique identifier for Person nodes, though of course in a real-life scenario we probably wouldn’t have one consistent identifier and instead would query the graph using a wide range of identifiers, matching criteria, query methods, etc.</p>
</div>
<div class="paragraph">
<p>Some examples of additional complexity we might add in a real-world scenario would be:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Using 'Personas' instead of 'People', to account for things like aliases.</p>
</li>
<li>
<p>A richer set of relationships between Persons and Crimes (i.e. Witness To, Victim Of, Suspected Of, Convicted Of)</p>
</li>
<li>
<p>Supporting traceability and auditing of data. In real life it’s very important to understand the lineage of the data, and how we could prove we have the right to hold that information (i.e. was it discovered as part of an investigation, is it publicly available, is it part of another document or related to another case, who entered the information and when, who has updated it, has it been verified, etc.).</p>
</li>
<li>
<p>Adding a robust security mechanism, to limit access to data to only those who have the right authorisation.</p>
</li>
<li>
<p>Use weighting for our searches and algorithms - for example, some crimes might be considered more dangerous than others (i.e. Violence and Sexual Offences is more serious than Shoplifting), or some relationships might be considered more reliable or closer (i.e 'Family' or 'Lives With' could be weighted more than 'Social Network')</p>
</li>
<li>
<p>Add More data! Neo4j is designed to handle massive graph workloads, which you would expect to see in a real-world POLE data set.</p>
</li>
</ul>
</div>
</div>
</div>
</slide>
</carousel>
</article>