├── README.md
└── SQL
├── Persons
├── Preprocess
│ ├── App.config
│ ├── Processor.csproj
│ ├── Processor.sln
│ └── Program.cs
├── README.md
├── bulk_insert.sql
├── invalidate_predicates.sql
├── predicate_functions.sql
└── predicates.sql
├── README.md
├── page_compression.sql
└── scripts.sql
/README.md:
--------------------------------------------------------------------------------
1 |
Akinator like engine
2 | A collegue has approached to us with a question on how Akinator engine may work.
3 | To our shame we have never heard about this amazing game before. To fill the gap we have immediately started to play it, and have identified it as a Troubleshooting solver.
4 | It took us a couple of minutes to come up with a brilliant solution: "We just need to google and find the engine in the internet". :-)
5 | Unfortunately, this led to nowhere, as no Akinator itself is open sourced, and no other good quality open source solutions are available.
6 | After another hour we have got two more ideas:
7 |
8 | - The task should fit into SQL;
9 | - The task is a good candidate for a neural network.
10 |
11 | In fact, the first might be required to teach the second, so we have decided to formalize the problem in terms of SQL, while still keeping in mind a neural network.
12 | SQL solution
13 | We have selected SQL Server as a database to implement our solution. A similar implementation is possible in other SQL (DB2, Oracle, MySql, SQLite), or NoSQL databases. SQL Server's facilities have allowed us to implement the task as a pure T-SQL API.
14 | Concepts
15 | The task can be defined as:"Guess an entity through a series of predicates".
16 | The database should contain following tables:
17 |
18 | Entity
- to define objects that can be found;
19 | PredicateType
- to define questions that can be asked about objects;
20 | Predicate
- to relate objects with answers to the questions.
21 |
22 | These tables is enough to construct an algorithm that takes as input a list of questions with answers, and offers the following question(s), if any (see Algorithm to suggest next question). But before building such an algorithm we must understand how can we populate these tables.
23 | We argued like this:
24 |
25 | - entities have properties;
26 | - predicates are based on properties of entities.
27 |
28 | Having entities with properties we can:
29 |
30 | - populate
Entity
;
31 | - mine properties to populate
PredicateType
;
32 | - populate
Predicate
based on answers.
33 |
34 | Thus, the database should also contain following tables:
35 |
36 | PropertyType
- to define different types of properties that entities can have;
37 | Property
- to define properties per entity.
38 |
39 | Test data
40 | Samples are required to evaluate the quality of the implementation. It took awhile to find such a data, mainly due to the problem with formulation of the search query. We have found the DBpedia - a crowd-sourced community effort to extract structured information from Wikipedia and make this information available on the Web.
41 | Many interesting datasets are collected there. We have decided to try Person dataset, which we got in cvs format from http://web.informatik.uni-mannheim.de/DBpediaAsTables/DBpediaClasses.htm. It contains information for more than 1.5 million persons, with several hundreds of different types of properties.
42 | Through a sequence of simple manipulations (see later in Load Persons) we have imported this cvs into PropertyType
and into Property
tables.
43 | Data mining
44 | At the following stage we looked into data, calculated use counts per each property type, and per property value. This has helped us to formulate several dozen questions about persons, like: "Is he/she living person?", "Is he/she politician?", "Is he/she artist?", "Is he/she writer?", "Is he/she tall?", "Is he a male?".
45 | We have found that there are questions that split whole set of persons into two more or less equal subsets. Other questions subset rather small set of persons. Yet other questions have fuzzy meaning, or are based on impresice property values (e.g. what does it mean "tall", or what to do with property "sex" that is defined not for all persons?)
46 | Looking more closely we can see that questions might be related. Consider that if "Is football player?" is true, then "Is sportsman?" is true also; or if "Was born somewhere in Europe?" is false then "Was born in France?" is also false. One way to represent such relations between questions is through hierarchy:
47 |
48 | - Is sportsman?
49 |
50 | - Is football player?
51 | - ...
52 |
53 |
54 | - Was born somewhere in Europe?
55 |
56 | - Was born in France?
57 | - ...
58 |
59 |
60 | - ...
61 |
62 | Sql definitions
63 | Let's define tables.
64 | Table Entity
defines objects:
65 | create table Data.Entity
66 | (
67 | EntityID int not null primary key
68 | );
69 | where
70 | EntityID
- is an object identity.
71 | Table PredicateType
defines predicate types:
72 | create table Data.PredicateType
73 | (
74 | PredicateID hierarchyid not null primary key,
75 | Name nvarchar(128) not null unique,
76 | Expression nvarchar(max) null,
77 | Computed bit not null default 0,
78 | ScopePredicateID hierarchyid null,
79 | Hidden bit not null default 0,
80 | Imprecise bit not null default 0
81 | );
82 | where
83 |
84 | PredicateID
- hierarchy ID that uniquely defines a predicate type.
85 | Name
- a unique predicate name in form: 'IsLivingPerson'
, 'IsMale'
, 'IsPolitician'
. Name can be seen as a question in human readable form.
86 | Expression
- an sql source used to evaluate the predicate. Usually it is of the form: Data.Predicate_IsLivingPerson()
. If Computed = 0
then this source is used to populate Data.Predicate
table; otherwise when Computed = 1
this source is used every time to get entities that match the predicate.
87 | Computed
- indicates whether to store entities that match the predicate in Data.Predicate
table (value is 0
), or to evaluate Expression
each time a predicate is requested (value is 1
).
88 | ScopePredicateID
- if specified, then the value defines the scope of PredicateID
(e.g. "IsMale", "IsFemale" predicates are defined not for all persons, but only for those having "Sex" property; in this case we define "Sex" preicate, and "IsMale", "IsFemale" refer to "Sex" as a scope).
89 | Hidden
- indicates that the predicate should not be offered (value is 1
).
90 | Imprecise
- indicates whether the predicate is not precise, meanning that some irrelevant objects might be matched by the predicates, and some relevant object might be not matched. (E.g. "IsTall" is a imprecise predicate as the answer considerably depends on player. Answer to such a question should always be considered as "probalby")
91 |
92 | Table Predicate
stores entities for which predicate is true:
93 | create table Data.Predicate
94 | (
95 | PredicateID hierarchyid not null,
96 | EntityID int not null,
97 | constraint PK_Predicate primary key clustered(PredicateID, EntityID),
98 | constraint IX_Predicate_Entity unique(EntityID, PredicateID),
99 | constraint FK_Predicate_Entity foreign key(EntityID)
100 | references Data.Entity(EntityID)
101 | on update cascade
102 | on delete cascade
103 | );
104 | where
105 |
106 | PredicateID
- a predicate reference;
107 | EntityID
- an entity reference.
108 |
109 | Table PropertyType
defines types of properties:
110 | create table Data.PropertyType
111 | (
112 | PropertyID int not null constraint PK_PropertyType primary key,
113 | Name nvarchar(128) not null,
114 | Type nvarchar(256) not null,
115 | index IX_PropertyType(Name)
116 | );
117 | where
118 |
119 | PropertyID
- a unique property ID;
120 | Name
- a property name;
121 | Type
- a property type.
122 |
123 | Table Property defines object properties:
124 | create table Data.Property
125 | (
126 | EntityID int not null,
127 | PropertyID int not null,
128 | Value nvarchar(4000) null,
129 | constraint FK_Property_Entity foreign key(EntityID)
130 | references Data.Entity(EntityID)
131 | on update cascade
132 | on delete cascade,
133 | index IX_Property_Property clustered(PropertyID, EntityID),
134 | index IX_Property_Entity(EntityID, PropertyID)
135 | );
136 | where
137 |
138 | EntityID
- is an entity reference;
139 | PropertyID
- refers to a preperty type;
140 | Value
- a property value.
141 |
142 | Together we had a heated debate on whether Data.Entity
is required at all,
143 | and if it is required then it might worth to add more info (like name or description) to it.
144 | We have agreed that something like this is required: either table or inexed view based on Data.Property
or on Data.Predicate
tables.
145 | In favor of the table decision it says that we can build foreign keys.
146 | As for additional columns to Data.Entity
the argument was that the Data.Property
already contains entity properties, and it is not exactly clear what property should be added directly to Data.Entity
.
147 |
148 | Predicate definitions
149 | A question definition translated into SQL would look like a query against Property
table, like the following:
150 | select EntityID from Data.Property where PropertyID = @livingPersonPropertID
151 | or
152 | select EntityID from Data.Property where PropertyID = @sexProperyID and TextValue = 'male'
153 | Further, these queries are wrapped into sql functions:
154 | select * from Data.Predicate_IsLivingPerson()
155 | or
156 | select * from Data.Predicate_IsMale()
157 | To manage predicates we have defined several simple stored procedures:
158 | -- Defines and populates a predicate
159 | create procedure Data.DefinePredicate
160 | (
161 | -- A predicate name to define.
162 | @name nvarchar(128),
163 | -- A predicate expression.
164 | @expression nvarchar(max) = null,
165 | -- Computed indicator
166 | @computed bit = 0,
167 | -- Optional parent predicate.
168 | @parent nvarchar(128) = null,
169 | -- Optional scope predicate.
170 | @scope nvarchar(128) = null,
171 | -- Optional value that indicates that the predicate is hidden.
172 | @hidden bit = 0,
173 | -- Indicates whether the predicate lacks accuracy. Default is 0.
174 | @imprecise bit = 0,
175 | -- 1 (default) to populate the predicate immediately.
176 | @populate bit = 1
177 | );
178 |
179 | -- Deletes a predicate.
180 | create procedure Data.DeletePredicate
181 | (
182 | -- A predicate name to define.
183 | @name nvarchar(128) = null
184 | );
185 |
186 | -- Invalidates a predicate.
187 | create procedure Data.InvalidatePredicate
188 | (
189 | -- A predicate name.
190 | @name nvarchar(128) = null
191 | );
192 |
193 | -- Invalidates all predicates.
194 | create procedure Data.InvalidatePredicates();
195 | and a couple of utility functions:
196 | create function Data.GetPropertyID(@name nvarchar(128))
197 | returns int
198 | as
199 | begin
200 | return (select PropertyID from Data.PropertyType where Name = @name);
201 | end;
202 |
203 | create function Data.GetPredicateID(@name nvarchar(128))
204 | returns hierarchyid
205 | as
206 | begin
207 | return (select PredicateID from Data.PredicateType where Name = @name);
208 | end;
209 | Now, when you want to define a new predicate, you follow these steps:
210 | - Define a predicate function that returns a set of entities that apply to a question, like this:
211 | create function Data.Predicate_IsActor()
212 | returns table
213 | as
214 | return
215 | select
216 | EntityID
217 | from
218 | Data.Property
219 | where
220 | (PropertyID = Data.GetPropertyID('22-rdf-syntax-ns#type_label')) and
221 | (TextValue = 'actor');
222 | - Define a predicate like this:
223 | execute Data.DefinePredicate
224 | @name = 'IsActor',
225 | @expression = 'Data.Predicate_IsActor()';
226 | While you are experimenting with questions you might want to reformulate the question, or delete the question. So to delete the question you call:
227 | execute Data.DeletePredicate @name = 'IsActor'
228 | To invalidate predicate (delete and repopulate relevant data into Data.Predicate
table) you call:
229 | execute Data.InvalidatePredicate @name = 'IsActor'
230 | To invalidate all predicates (delete and repopulate all data into Data.Predicate
table) you call:
231 | execute Data.InvalidatePredicates
232 | Algorithm to suggest next questions
233 | Core algorithm spins around Predicate
, Entity
, and PredicateType
tables.
234 | Assuming we have P(i)
- predicates, and A(i)
- answers, where i = 1..n
; let answer A(i)
be 0
for "no", and 1
for "yes". We are going to build a select that returns next predicates.
235 | The initial part of select gets subsets of entities that match the predicates:
236 | with P1 as -- P(1)
237 | (
238 | select EntityID from Data.Predicate where PredicateID = @p1
239 | ),
240 | P2 as -- P(2)
241 | (
242 | select EntityID from Data.Predicate where PredicateID = @p2
243 | ),
244 | ...
245 | Pn as -- P(n)
246 | (
247 | select EntityID from Data.Predicate where PredicateID = @pn
248 | ),
249 | at the next step we get entities that are matched by those predicates:
250 | M as
251 | (
252 | select EntityID from Data.Entity
253 |
254 | -- Intersect those Pi that has A(i) = 1
255 | intersect
256 | select EntityID from Pi -- where A(i) = 1
257 | ...
258 |
259 | -- Except those Pj that has A(j) = 0
260 | except
261 | select EntityID from Pj -- where A(j) = 0
262 | ...
263 | ),
264 | Now, we can query predicates for matched entities, except those predicates that has been already used:
265 | P as
266 | (
267 | select
268 | P.PredicateID,
269 | count(*) EntityCount,
270 | (select count(*) from M) TotalCount
271 | from
272 | Data.Predicate P
273 | inner join
274 | M
275 | on
276 | P.EntityID = M.EntityID
277 | where
278 | P.PredicateID not in (@p1, @p2, ..., @pn)
279 | group by
280 | P.PredicateID
281 | )
282 | where
283 |
284 | EntityCount
- is number of entities that match a specified predicate;
285 | TotalCount
- a total number of entities that match input predicates.
286 |
287 | As a final result we can return first several predicates that split set of entities more evenly:
288 | select top(5) * from P order by abs(TotalCount - EntityCount * 2);
289 | For example, if we have n = 5
, and A(1) = A(3) = 1, A(2) = A(4) = A(5) = 0
then the select will look like this:
290 | with P1 as -- P(1), A(1) = 1
291 | (
292 | select EntityID from Data.Predicate where PredicateID = @p1
293 | ),
294 | P2 as -- P(2), A(2) = 0
295 | (
296 | select EntityID from Data.Predicate where PredicateID = @p2
297 | ),
298 | P3 as -- P(3), A(3) = 1
299 | (
300 | select EntityID from Data.Predicate where PredicateID = @p3
301 | ),
302 | P4 as -- P(4), A(4) = 0
303 | (
304 | select EntityID from Data.Predicate where PredicateID = @p4
305 | ),
306 | P5 as -- P(5), A(5) = 0
307 | (
308 | select EntityID from Data.Predicate where PredicateID = @p5
309 | ),
310 | M as
311 | (
312 | select EntityID from Data.Entity
313 | intersect
314 | select EntityID from P1
315 | intersect
316 | select EntityID from P3
317 | except
318 | select EntityID from P2
319 | except
320 | select EntityID from P4
321 | except
322 | select EntityID from P5
323 | ),
324 | P as
325 | (
326 | select
327 | P.PredicateID,
328 | count(*) EntityCount,
329 | (select count(*) from M) TotalCount
330 | from
331 | Data.Predicate P
332 | inner join
333 | M
334 | on
335 | P.EntityID = M.EntityID
336 | where
337 | P.PredicateID not in (@p1, @p2, @p3, @p4, @p5)
338 | group by
339 | P.PredicateID
340 | )
341 | select top(5) * from P order by abs(TotalCount - EntityCount * 2);
342 | Now, let's complicate the task, and assume fuzzy answers:
343 |
344 | 0
- for "no";
345 | (0, 0.5)
- for "probably no";
346 | 0.5
- for "don't know";
347 | (0.5, 1)
- for "probably yes";
348 | 1
- for "yes".
349 |
350 | Fuzzy answers should not cut subsets of entities but prioritize order of predicates returned.
351 | Lets's start from "don't know" answer. In this case we should equally accept both subsets of entities that match and that don't match the predicate. The only impact on result from such answer is that the relevant predicate is excluded from the next offers.
352 | So, lets assume in the previous exmaple that we have n = 5
, and A(1) = 1, A(3) = 0.5, A(2) = A(4) = A(5) = 0
then the select will look like this:
353 | The result select will look like this:
354 | with P1 as -- P(1), A(1) = 1
355 | (
356 | select EntityID from Data.Predicate where PredicateID = @p1
357 | ),
358 | P2 as -- P(2), A(2) = 0
359 | (
360 | select EntityID from Data.Predicate where PredicateID = @p2
361 | ),
362 | P3 as -- P(3), A(3) = 0.5
363 | (
364 | select EntityID from Data.Predicate where PredicateID = @p3
365 | ),
366 | P4 as -- P(4), A(4) = 0
367 | (
368 | select EntityID from Data.Predicate where PredicateID = @p4
369 | ),
370 | P5 as -- P(5), A(5) = 0
371 | (
372 | select EntityID from Data.Predicate where PredicateID = @p5
373 | ),
374 | M as
375 | (
376 | select EntityID from Data.Entity
377 | intersect
378 | select EntityID from P1
379 | -- intersect
380 | -- select EntityID from P3
381 | except
382 | select EntityID from P2
383 | except
384 | select EntityID from P4
385 | except
386 | select EntityID from P5
387 | ),
388 | P as
389 | (
390 | select
391 | P.PredicateID,
392 | count(*) EntityCount,
393 | (select count(*) from M) TotalCount
394 | from
395 | Data.Predicate P
396 | inner join
397 | M
398 | on
399 | P.EntityID = M.EntityID
400 | where
401 | P.PredicateID not in (@p1, @p2, @p3, @p4, @p5)
402 | group by
403 | P.PredicateID
404 | )
405 | select top(5) * from P order by abs(TotalCount - EntityCount * 2);
406 | Notice that P3
is not used in M
.
407 | The final step is to account "probably" answers. Such answers give weight to each entity. Offered predicates should be ordered according to weight of entities they are based on.
408 | Assuming we have P(i)
- predicates, and A(i)
- answers, where i = 1..n
; and assume that A(k), and A(l) have "probably" answers. In this case let's define weighted entities:
409 | E as
410 | (
411 | select
412 | EntityID,
413 | iif(EntityID in (select EntityID from Pk), @ak, 1 - @ak) *
414 | iif(EntityID in (select EntityID from Pl), @al, 1 - @al) Weight
415 | from
416 | M
417 | ),
418 | where
419 | Weight
- an entity weight.
420 | Now, the query for next predicates can be written like this:
421 | P as
422 | (
423 | select distinct
424 | E.Weight,
425 | P.PredicateID,
426 | count(*) over(partition by E.Weight, P.PredicateID) EntityCount,
427 | count(*) over(partition by E.Weight) TotalCount
428 | from
429 | Data.Predicate P
430 | inner join
431 | E
432 | on
433 | P.EntityID = E.EntityID
434 | where
435 | P.PredicateID not in (@p1, @p2, ..., @pn)
436 | )
437 | where
438 |
439 | Weight
- a predicate weight.
440 | EntityCount
- is number of entities that match a specified predicate per weight;
441 | TotalCount
- a total number of entities that match input predicates per weight.
442 |
443 | The final result will be almost the same as earlier but ordered at first by weight:
444 | select top(5) * from P order by Weight desc, abs(TotalCount - EntityCount * 2);
445 | So, lets assume in our previous exmaple that we have n = 5
, and A(1) = 1, A(3) = 0.5, A(2) = 0, A(4) = 0.3, A(5) = 0.8
then the select will look like this:
446 | with P1 as -- P(1), A(1) = 1
447 | (
448 | select EntityID from Data.Predicate where PredicateID = @p1
449 | ),
450 | P2 as -- P(2), A(2) = 0
451 | (
452 | select EntityID from Data.Predicate where PredicateID = @p2
453 | ),
454 | P3 as -- P(3), A(3) = 0.5
455 | (
456 | select EntityID from Data.Predicate where PredicateID = @p3
457 | ),
458 | P4 as -- P(4), A(4) = 0.3
459 | (
460 | select EntityID from Data.Predicate where PredicateID = @p4
461 | ),
462 | P5 as -- P(5), A(5) = 0.8
463 | (
464 | select EntityID from Data.Predicate where PredicateID = @p5
465 | ),
466 | M as
467 | (
468 | select EntityID from Data.Entity
469 | intersect
470 | select EntityID from P1
471 | -- intersect
472 | -- select EntityID from P3
473 | except
474 | select EntityID from P2
475 | -- except
476 | -- select EntityID from P4
477 | -- except
478 | -- select EntityID from P5
479 | ),
480 | E as
481 | (
482 | select
483 | EntityID,
484 | iif(EntityID in (select EntityID from P4), 0.3, 0.7) *
485 | iif(EntityID in (select EntityID from P5), 0.8, 0.2) Weight
486 | from
487 | M
488 | ),
489 | P as
490 | (
491 | select distinct
492 | E.Weight,
493 | P.PredicateID,
494 | count(*) over(partition by E.Weight, P.PredicateID) EntityCount,
495 | count(*) over(partition by E.Weight) TotalCount
496 | from
497 | Data.Predicate P
498 | inner join
499 | E
500 | on
501 | P.EntityID = E.EntityID
502 | where
503 | P.PredicateID not in (@p1, @p2, @p3, @p4, @p5)
504 | )
505 | select top(5) * from P order by Weight desc, abs(TotalCount - EntityCount * 2);
506 | That is the most complex form of select that algorithm should produce.
507 | Consider now results of these selects.
508 | If there are rows in result set, then we can either offer predicate from the first row, or, if we want to model some randomness, we can at times go to some other predicate from those returned.
509 | If no rows are returned then we are finished with offers. The only thing we can return is a set of matched entities that is:
510 | select * from M;
511 | or in case or "probably" answers:
512 | select * from E;
513 | We might want to join those selects with Data.Property
table to bring some entity properties, like name, or description.
514 | Implementation of algorithm
515 | Now algorithm is clear. The deal is just to implement it. We can see that the structure of select depends considerably on number of questions and type of answers.
516 | To deal with this we use dynamic SQL. In the past we wrote an article on "Dealing with dynamic SQL in SQL Server".
517 | The idea was to use XQuery as a SQL template language. At first you might think that this is too radical step but after a close look you will observe that it might be the most straightforward solution to deal with dynamic SQL. Just consider an XQuery snapshot that builds "Pi as (...), ..."
text:
518 | '<sql>with </sql>,
519 |
520 | for $predicate in $predicates
521 | let $row := xs:integer($predicate/@Row)
522 | let $predicateID := xs:string($predicate/@PredicateID)
523 | let $name := xs:string($predicate/@Name)
524 | return
525 | <sql>P{$row} as -- <name>{$name}</name>
526 | (
527 | select EntityID from Data.Predicate where PredicateID = <string>{$predicateID}</string>
528 | ),
529 | </sql>'
530 | We have defined two SQL functions that build SQL text for such input xml:
531 | create function Dynamic.GetSQL_GetNextPredicate
532 | (
533 | -- Request parameters.
534 | @params xml
535 | );
536 |
537 | create function Dynamic.GetSQL_GetEntities
538 | (
539 | -- Request parameters.
540 | @params xml,
541 | -- Optional property value to return.
542 | @property nvarchar(128)
543 | );
544 | and two more stored procedures one that offers new predicates, and the other that returns matched entities:
545 | -- Gets next predicates
546 | create procedure Data.GetNextPredicates
547 | (
548 | -- Request parameters.
549 | @params xml,
550 | -- Result as a predicate
551 | @result xml output
552 | );
553 |
554 | -- Gets entities for predicates
555 | create procedure Data.GetEntities
556 | (
557 | -- Request parameters.
558 | @params xml,
559 | -- Optional property value to return.
560 | @property nvarchar(128)
561 | );
562 | The input for these procedures are in the form of xml like this:
563 | <request>
564 | <question name="IsLivingPerson" answer="1"/>
565 | <question name="IsFootballPlayer" answer="0"/>
566 | <question name="IsArtist" answer="0.3"/>
567 | ...
568 | <request>
569 |
570 | Data.GetNextPredicates
returns an xml result fragment with next suggested predicates in the form:
571 | <question name="IsPolitician"/>
572 | <question name="IsReligious"/>
573 | <question name="IsMilitary"/>
574 |
575 | Data.GetEntities
returns a set of entities with possible value of some property (like name or description).
576 | Cache of results
577 | At this point we could complete our explanation of the algorithm and its implementation, especially taking into account that performance over test data, which is more than 1.5 million of entities, is very good. Indeed, it take 100ms on average to build SQL, and from dozens milliseconds and up to 3 - 4 seconds to run the query. Execution plans look good, and there are no bottlenecks for scalability.
578 | But we have thought that we can do better! According to the algorithm there are just several best predicates on the top level; there are also not too many best predicates on the second level, and so on. We have estimated that we can cache different results for all requests, say, for up to ten or even more input predicates. This means that we can immediately give answers to different sets of inputs, and descend to a rather small set of remaining entities. On the remaining set, a regular, even non-cached, search works very fast.
579 | So, we will continue.
580 | Caching implementation
581 | We cache search offers in a tree. Each node in this tree:
582 |
583 | - has a node identifier;
584 | - refers to the parent node (parent offer); and
585 | - is classified with answer to the parent offer, and with new offered predicate.
586 |
587 | Path from any specific node to the root of the tree defines a set of questions and answers, and the node itself offers next predicate.
588 | This way cache table can be defined like this:
589 | create table Data.PredicateTree
590 | (
591 | ID int not null primary key,
592 | ParentID int not null,
593 | Answer decimal(2, 1) not null,
594 | PredicateID hierarchyid null,
595 | Populated bit not null default 0,
596 | constraint IX_PredicateTree unique(ParentID, Answer, PredicateID)
597 | );
598 | where
599 |
600 | ID
- a node identifier.
601 | ParentID
- reference to a parent node.
602 | Answer
- answer to the parent offer.
603 | PredicateID
- offered predicate; when value is null then this search brings no next predicate.
604 | Populated
- indicates whether it is a populated search result (1), or it is a row inserted to populate a descendant search result.
605 |
606 | How caching works
607 | Caching is integrated into the procedure Data.GetNextPredicates
.
608 |
609 | - When the
GetNextPredicates
is called, request's questions are sorted by PredicateID
. This is to reduce a number of permutations to store in the cache. This can be done, as an offer does not depend on order of questions but on whole set of questions only.
610 | PredicateTree
is checked to find a node that corresponds requested questions with answers.
611 | - If such node is found then offered predicates are returned.
612 | - Otherwise regular search is done, and results are cached into the
PredicateTree
.
613 |
614 | Decision Tree
615 | If you will look at caching from other perspective, and will decide to cache all data in such tree, then it can be qualified as a decition tree. The data contained in such table will be enough to guess any entity.
616 | Play the search
617 | We can guess a specific entity and start playing executing Data.GetNextPredicates
iteratively and answering offered questions.
618 | This way we shall reach to the point where no more predicates are offered. This way procedures either localized a minimal subset of entities or found required entity itself.
619 | We have defined a procedure Data.PlaySearch
that does exactly this. It plays the game. Among other roles this procedure populates the search cache.
620 | Sources
621 | Solution sources are published at github.com/nesterovsky-bros/KB.
622 | SQL Server scripts are found at github.com/nesterovsky-bros/KB/SQL.
623 | Steps to load DBpedia Persons data are described at github.com/nesterovsky-bros/KB/SQL/Persons.
624 | Thank you for your attention.
625 |
--------------------------------------------------------------------------------
/SQL/Persons/Preprocess/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SQL/Persons/Preprocess/Processor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0FE62647-456F-4731-9F5A-59658E11838F}
8 | Exe
9 | Properties
10 | KB
11 | Preprocess
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
61 |
--------------------------------------------------------------------------------
/SQL/Persons/Preprocess/Processor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processor", "Processor.csproj", "{0FE62647-456F-4731-9F5A-59658E11838F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {0FE62647-456F-4731-9F5A-59658E11838F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {0FE62647-456F-4731-9F5A-59658E11838F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {0FE62647-456F-4731-9F5A-59658E11838F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {0FE62647-456F-4731-9F5A-59658E11838F}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/SQL/Persons/Preprocess/Program.cs:
--------------------------------------------------------------------------------
1 | namespace KB
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Net;
7 | using System.Text;
8 |
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | var encoding = args[0];
14 | var cvs = args[1];
15 | var output = args[2];
16 | var rowsWritten = 0;
17 | var metadataWritten = false;
18 |
19 | using(var file =
20 | new StreamWriter(
21 | Path.Combine(output, "data.txt"),
22 | false,
23 | Encoding.Unicode))
24 | {
25 | foreach(var row in Rows(Lines(GetEncoding(encoding), cvs)))
26 | {
27 | if (!metadataWritten)
28 | {
29 | metadataWritten = true;
30 |
31 | var j = 0;
32 |
33 | using(var meta =
34 | new StreamWriter(
35 | Path.Combine(output, "metadata.txt"),
36 | false,
37 | Encoding.Unicode))
38 | {
39 | foreach(var value in row.Titles)
40 | {
41 | ++j;
42 | meta.Write(j);
43 | meta.Write("\t");
44 | meta.Write(value);
45 | meta.Write("\t");
46 | meta.WriteLine(Escape(row.Types[j - 1]));
47 | }
48 | }
49 | }
50 |
51 | var i = 0;
52 |
53 | foreach(var value in row.Values)
54 | {
55 | ++i;
56 |
57 | if (value != "NULL")
58 | {
59 | if (value.StartsWith("{") && value.EndsWith("}"))
60 | {
61 | var multivalues =
62 | value.Substring(1, value.Length - 2).Split('|');
63 |
64 | foreach(var multivalue in multivalues)
65 | {
66 | file.Write(row.RowNumber);
67 | file.Write("\t");
68 | file.Write(i);
69 | file.Write("\t");
70 | file.WriteLine(Escape(multivalue));
71 | }
72 | }
73 | else
74 | {
75 | file.Write(row.RowNumber);
76 | file.Write("\t");
77 | file.Write(i);
78 | file.Write("\t");
79 | file.WriteLine(Escape(value));
80 | }
81 | }
82 | }
83 |
84 | ++rowsWritten;
85 |
86 | if (rowsWritten % 10000 == 0)
87 | {
88 | Console.WriteLine("{0} rows has been written.", rowsWritten);
89 | }
90 | }
91 | }
92 |
93 | Console.WriteLine("Total {0} rows has been written.", rowsWritten);
94 | }
95 |
96 | public struct Row
97 | {
98 | public long RowNumber;
99 | public string[] Titles;
100 | public string[] Types;
101 | public string[] Values;
102 | }
103 |
104 | public static IEnumerable Rows(IEnumerable lines)
105 | {
106 | var row = 0L;
107 | var titles = null as string[];
108 | var types = null as string[];
109 |
110 | foreach(var line in lines)
111 | {
112 | ++row;
113 |
114 | var values = SplitLine(line);
115 |
116 | switch(row)
117 | {
118 | case 1:
119 | {
120 | titles = values;
121 |
122 | break;
123 | }
124 | case 2:
125 | case 3:
126 | {
127 | break;
128 | }
129 | case 4:
130 | {
131 | types = values;
132 |
133 | break;
134 | }
135 | default:
136 | {
137 | yield return new Row
138 | {
139 | RowNumber = row,
140 | Titles = titles,
141 | Types = types,
142 | Values = values
143 | };
144 |
145 | break;
146 | }
147 | }
148 | }
149 | }
150 |
151 | public static Encoding GetEncoding(string encoding)
152 | {
153 | if (string.IsNullOrWhiteSpace(encoding))
154 | {
155 | return Encoding.Default;
156 | }
157 |
158 | try
159 | {
160 | return Encoding.GetEncoding(encoding);
161 | }
162 | catch
163 | {
164 | return Encoding.GetEncoding(int.Parse(encoding));
165 | }
166 | }
167 |
168 | public static string Escape(string value)
169 | {
170 | return value == null ? null :
171 | WebUtility.UrlDecode(value).
172 | Replace('\t', ' ').
173 | Replace('\r', ' ').
174 | Replace('\n', ' ');
175 | }
176 |
177 | public static IEnumerable Lines(Encoding encoding, string cvs)
178 | {
179 | using(var stream =
180 | new FileStream(cvs, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
181 | using(var reader = new StreamReader(stream, encoding))
182 | {
183 | while (true)
184 | {
185 | var line = reader.ReadLine();
186 |
187 | if (line == null)
188 | {
189 | break;
190 | }
191 |
192 | yield return line;
193 | }
194 | }
195 | }
196 |
197 | private static string[] Delimiters = new[] { "\",\"" };
198 |
199 | public static string[] SplitLine(string line)
200 | {
201 | return line.Substring(1, line.Length - 2).Split(Delimiters, StringSplitOptions.None);
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/SQL/Persons/README.md:
--------------------------------------------------------------------------------
1 | Test data
2 | We use DBpedia's Person.csv dataset to train the engine.
3 |
4 | Preprocessor
5 | We preprocess Person.csv before loading it into the database.
6 | Preprocessor outputs two files:
7 |
8 | - Metadata.txt - file containing property definitions;
9 | - Data.txt - file containing properties for each person;
10 |
11 | Preprocessor is implemented as a simple C# program (see Preprocess project).
12 | Preprocessor is run like this:
13 | Preprocessor.exe {encoding} {path to person.csv} {path to output folder}
14 | where
15 |
16 | {encoding}
- csv's file encoding; place there 1252.
17 | {path to person.csv}
- path to input cvs file.
18 | {path to output folder}
- path to output folder.
19 |
20 | This step will run from 5 to 10 minutes.
21 | Load data
22 | At the next step we load persons into the database bulk_insert.sql.
23 | This is long running task, so be prepared it will work a hour of two.
24 | Define predicates
25 | Execute following scripts:
26 |
31 |
--------------------------------------------------------------------------------
/SQL/Persons/bulk_insert.sql:
--------------------------------------------------------------------------------
1 | -- Note: {path to output folder} - is a folder where preprocessor outputs files.
2 |
3 | --set ansi_warings off
4 |
5 | bulk insert Data.PropertyType
6 | from '{path to output folder}\metadata.txt'
7 | with(batchsize = 100000, datafiletype = 'widechar');
8 |
9 | bulk insert Data.Property
10 | from '{path to output folder}\data.txt'
11 | with(batchsize = 100000, datafiletype = 'widechar');
12 |
13 | -- Populate entities
14 | insert into Data.Entity(EntityID)
15 | select distinct EntityID from Data.Property;
16 |
--------------------------------------------------------------------------------
/SQL/Persons/invalidate_predicates.sql:
--------------------------------------------------------------------------------
1 | execute Data.InvalidatePredicates @debug = 1
2 |
--------------------------------------------------------------------------------
/SQL/Persons/predicate_functions.sql:
--------------------------------------------------------------------------------
1 | CREATE function[Data].[Predicate_DealsWithRaceHorses]()
2 | returns table
3 | as
4 | return
5 | select
6 | EntityID
7 | from
8 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
9 | where
10 | Value like '%Racehorse%'
11 |
12 | GO
13 | SET ANSI_NULLS ON
14 | GO
15 | SET QUOTED_IDENTIFIER ON
16 | GO
17 | CREATE function[Data].[Predicate_HasAwards]()
18 | returns table
19 | as
20 | return
21 | select
22 | EntityID
23 | from
24 | Data.GetEntityProperties('award_label')
25 |
26 |
27 | GO
28 | SET ANSI_NULLS ON
29 | GO
30 | SET QUOTED_IDENTIFIER ON
31 | GO
32 | CREATE function[Data].[Predicate_HasBlackHairs]()
33 | returns table
34 | as
35 | return
36 | select
37 | EntityID
38 | from
39 | Data.GetEntityProperties('hairColor')
40 | where
41 | Value in (
42 | 'Black',
43 | 'Dark Brown/Black',
44 | 'Jet Black',
45 | 'Black (natural)'
46 | )
47 |
48 |
49 | GO
50 | SET ANSI_NULLS ON
51 | GO
52 | SET QUOTED_IDENTIFIER ON
53 | GO
54 | CREATE function[Data].[Predicate_HasBrownHairs]()
55 | returns table
56 | as
57 | return
58 | select
59 | EntityID
60 | from
61 | Data.GetEntityProperties('hairColor')
62 | where
63 | Value in (
64 | 'Brown',
65 | 'Brunette',
66 | 'Dark Brown',
67 | 'Light brown',
68 | 'Ash Brown',
69 | 'Brown (dyed)'
70 | )
71 |
72 |
73 | GO
74 | SET ANSI_NULLS ON
75 | GO
76 | SET QUOTED_IDENTIFIER ON
77 | GO
78 | CREATE function[Data].[Predicate_HasChef]()
79 | returns table
80 | as
81 | return
82 | select
83 | EntityID
84 | from
85 | Data.GetEntityProperties('HasChef')
86 | where
87 | (Value in (N'כן', '1', 'yes', 'true'))
88 |
89 |
90 | GO
91 | SET ANSI_NULLS ON
92 | GO
93 | SET QUOTED_IDENTIFIER ON
94 | GO
95 | CREATE function[Data].[Predicate_HasLightHairs]()
96 | returns table
97 | as
98 | return
99 | select
100 | EntityID
101 | from
102 | Data.GetEntityProperties('hairColor')
103 | where
104 | Value in (
105 | 'Blonde',
106 | 'blond',
107 | 'Dark Blonde',
108 | 'dark blond',
109 | 'Honey Brown',
110 | 'Platinum blond'
111 | )
112 |
113 |
114 | GO
115 | SET ANSI_NULLS ON
116 | GO
117 | SET QUOTED_IDENTIFIER ON
118 | GO
119 | CREATE function[Data].[Predicate_HasReddishHairs]()
120 | returns table
121 | as
122 | return
123 | select
124 | EntityID
125 | from
126 | Data.GetEntityProperties('hairColor')
127 | where
128 | Value in (
129 | 'Chestnut Brown',
130 | 'Red',
131 | 'Auburn',
132 | 'Burgundy',
133 | 'Reddish Brown'
134 | )
135 |
136 |
137 | GO
138 | SET ANSI_NULLS ON
139 | GO
140 | SET QUOTED_IDENTIFIER ON
141 | GO
142 | CREATE function[Data].[Predicate_IsActor]()
143 | returns table
144 | as
145 | return
146 | select
147 | EntityID
148 | from
149 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
150 | where
151 | (Value in ('actor'))
152 |
153 | GO
154 | SET ANSI_NULLS ON
155 | GO
156 | SET QUOTED_IDENTIFIER ON
157 | GO
158 | CREATE function[Data].[Predicate_IsAmericanFootballPlayer]()
159 | returns table
160 | as
161 | return
162 | select
163 | EntityID
164 | from
165 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
166 | where
167 | (Value = 'american football player')
168 |
169 |
170 | GO
171 | SET ANSI_NULLS ON
172 | GO
173 | SET QUOTED_IDENTIFIER ON
174 | GO
175 | CREATE function[Data].[Predicate_IsArchitect]()
176 | returns table
177 | as
178 | return
179 | select
180 | EntityID
181 | from
182 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
183 | where
184 | (Value = 'architect')
185 |
186 | GO
187 | SET ANSI_NULLS ON
188 | GO
189 | SET QUOTED_IDENTIFIER ON
190 | GO
191 | CREATE function[Data].[Predicate_IsArtist]()
192 | returns table
193 | as
194 | return
195 | select
196 | EntityID
197 | from
198 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
199 | where
200 | (Value = 'artist')
201 |
202 | GO
203 | SET ANSI_NULLS ON
204 | GO
205 | SET QUOTED_IDENTIFIER ON
206 | GO
207 |
208 | CREATE function[Data].[Predicate_IsAstronaut]()
209 | returns table
210 | as
211 | return
212 | select
213 | EntityID
214 | from
215 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
216 | where
217 | (Value = 'http://dbpedia.org/ontology/Astronaut')
218 |
219 | GO
220 | SET ANSI_NULLS ON
221 | GO
222 | SET QUOTED_IDENTIFIER ON
223 | GO
224 | CREATE function[Data].[Predicate_IsBaroqueComposer]()
225 | returns table
226 | as
227 | return
228 | select
229 | EntityID
230 | from
231 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
232 | where
233 | (Value = 'BaroqueComposers')
234 |
235 | GO
236 | SET ANSI_NULLS ON
237 | GO
238 | SET QUOTED_IDENTIFIER ON
239 | GO
240 | CREATE function[Data].[Predicate_IsBaseballPlayer]()
241 | returns table
242 | as
243 | return
244 | select
245 | EntityID
246 | from
247 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
248 | where
249 | Value in (
250 | 'http://dbpedia.org/ontology/BaseballPlayer',
251 | 'http://umbel.org/umbel/rc/BaseballPlayer'
252 | )
253 |
254 |
255 | GO
256 | SET ANSI_NULLS ON
257 | GO
258 | SET QUOTED_IDENTIFIER ON
259 | GO
260 | CREATE function[Data].[Predicate_IsBasketballPlayer]()
261 | returns table
262 | as
263 | return
264 | select
265 | EntityID
266 | from
267 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
268 | where
269 | (Value like 'BasketballPlayer%')
270 |
271 |
272 | GO
273 | SET ANSI_NULLS ON
274 | GO
275 | SET QUOTED_IDENTIFIER ON
276 | GO
277 |
278 | CREATE function[Data].[Predicate_IsBeautyQueen]()
279 | returns table
280 | as
281 | return
282 | select
283 | EntityID
284 | from
285 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
286 | where
287 | (Value = 'http://dbpedia.org/ontology/BeautyQueen')
288 |
289 | GO
290 | SET ANSI_NULLS ON
291 | GO
292 | SET QUOTED_IDENTIFIER ON
293 | GO
294 | CREATE function[Data].[Predicate_IsBoxer]()
295 | returns table
296 | as
297 | return
298 | select
299 | EntityID
300 | from
301 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
302 | where
303 | (Value like 'Boxer%')
304 |
305 |
306 | GO
307 | SET ANSI_NULLS ON
308 | GO
309 | SET QUOTED_IDENTIFIER ON
310 | GO
311 | CREATE function[Data].[Predicate_IsBusinessPerson]()
312 | returns table
313 | as
314 | return
315 | select
316 | EntityID
317 | from
318 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
319 | where
320 | (Value = 'http://dbpedia.org/ontology/BusinessPerson')
321 |
322 | GO
323 | SET ANSI_NULLS ON
324 | GO
325 | SET QUOTED_IDENTIFIER ON
326 | GO
327 | CREATE function[Data].[Predicate_IsChessPlayer]()
328 | returns table
329 | as
330 | return
331 | select
332 | EntityID
333 | from
334 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
335 | where
336 | (Value like '%ChessPlayer%')
337 |
338 | GO
339 | SET ANSI_NULLS ON
340 | GO
341 | SET QUOTED_IDENTIFIER ON
342 | GO
343 | CREATE function[Data].[Predicate_IsCoach]()
344 | returns table
345 | as
346 | return
347 | select
348 | EntityID
349 | from
350 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
351 | where
352 | (Value like '%Coach%')
353 |
354 |
355 | GO
356 | SET ANSI_NULLS ON
357 | GO
358 | SET QUOTED_IDENTIFIER ON
359 | GO
360 | CREATE function[Data].[Predicate_IsComedian]()
361 | returns table
362 | as
363 | return
364 | select
365 | EntityID
366 | from
367 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
368 | where
369 | (Value in
370 | ('http://dbpedia.org/ontology/Comedian', 'http://umbel.org/umbel/rc/Comedian'))
371 |
372 | GO
373 | SET ANSI_NULLS ON
374 | GO
375 | SET QUOTED_IDENTIFIER ON
376 | GO
377 | CREATE function[Data].[Predicate_IsComposer]()
378 | returns table
379 | as
380 | return
381 | select
382 | EntityID
383 | from
384 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
385 | where
386 | (Value like '%Composer%')
387 |
388 | GO
389 | SET ANSI_NULLS ON
390 | GO
391 | SET QUOTED_IDENTIFIER ON
392 | GO
393 | CREATE function[Data].[Predicate_IsCriminal]()
394 | returns table
395 | as
396 | return
397 | select
398 | EntityID
399 | from
400 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
401 | where
402 | (Value like 'criminal%')
403 |
404 | GO
405 | SET ANSI_NULLS ON
406 | GO
407 | SET QUOTED_IDENTIFIER ON
408 | GO
409 | CREATE function[Data].[Predicate_IsFemale]()
410 | returns table
411 | as
412 | return
413 | select
414 | EntityID
415 | from
416 | Data.GetEntityProperties('gender_label')
417 | where
418 | (Value = 'Female')
419 |
420 |
421 | GO
422 | SET ANSI_NULLS ON
423 | GO
424 | SET QUOTED_IDENTIFIER ON
425 | GO
426 | CREATE function[Data].[Predicate_IsFictionalCharacter]()
427 | returns table
428 | as
429 | return
430 | select
431 | EntityID
432 | from
433 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
434 | where
435 | (Value = 'fictional character')
436 |
437 | GO
438 | SET ANSI_NULLS ON
439 | GO
440 | SET QUOTED_IDENTIFIER ON
441 | GO
442 | CREATE function[Data].[Predicate_IsFigureSkater]()
443 | returns table
444 | as
445 | return
446 | select
447 | EntityID
448 | from
449 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
450 | where
451 | (Value like '%FigureSkater%')
452 |
453 |
454 | GO
455 | SET ANSI_NULLS ON
456 | GO
457 | SET QUOTED_IDENTIFIER ON
458 | GO
459 | CREATE function[Data].[Predicate_IsFootballPlayer]()
460 | returns table
461 | as
462 | return
463 | select
464 | EntityID
465 | from
466 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
467 | where
468 | Value like 'FootballPlayer%'
469 |
470 |
471 | GO
472 | SET ANSI_NULLS ON
473 | GO
474 | SET QUOTED_IDENTIFIER ON
475 | GO
476 | CREATE function[Data].[Predicate_IsFromGreekMythology]()
477 | returns table
478 | as
479 | return
480 | select
481 | EntityID
482 | from
483 | Data.GetEntityProperties('mythology_label')
484 | where
485 | Value in (
486 | 'Greek mythology',
487 | '"Greek mythology"'
488 | )
489 |
490 | GO
491 | SET ANSI_NULLS ON
492 | GO
493 | SET QUOTED_IDENTIFIER ON
494 | GO
495 | CREATE function[Data].[Predicate_IsGymnast]()
496 | returns table
497 | as
498 | return
499 | select
500 | EntityID
501 | from
502 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
503 | where
504 | Value in ('Gymnast', 'gymnast')
505 |
506 | GO
507 | SET ANSI_NULLS ON
508 | GO
509 | SET QUOTED_IDENTIFIER ON
510 | GO
511 |
512 | CREATE function[Data].[Predicate_IsHistorian]()
513 | returns table
514 | as
515 | return
516 | select
517 | EntityID
518 | from
519 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
520 | where
521 | (Value = 'http://dbpedia.org/ontology/Historian')
522 |
523 | GO
524 | SET ANSI_NULLS ON
525 | GO
526 | SET QUOTED_IDENTIFIER ON
527 | GO
528 | CREATE function[Data].[Predicate_IsIceHockeyPlayer]()
529 | returns table
530 | as
531 | return
532 | select
533 | EntityID
534 | from
535 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
536 | where
537 | (Value = 'ice hockey player')
538 |
539 |
540 | GO
541 | SET ANSI_NULLS ON
542 | GO
543 | SET QUOTED_IDENTIFIER ON
544 | GO
545 |
546 | CREATE function[Data].[Predicate_IsJournalist]()
547 | returns table
548 | as
549 | return
550 | select
551 | EntityID
552 | from
553 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
554 | where
555 | (Value like 'Journalist%')
556 |
557 | GO
558 | SET ANSI_NULLS ON
559 | GO
560 | SET QUOTED_IDENTIFIER ON
561 | GO
562 |
563 | CREATE function[Data].[Predicate_IsJudge]()
564 | returns table
565 | as
566 | return
567 | select
568 | EntityID
569 | from
570 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
571 | where
572 | (Value = 'judge')
573 |
574 | GO
575 | SET ANSI_NULLS ON
576 | GO
577 | SET QUOTED_IDENTIFIER ON
578 | GO
579 | CREATE function[Data].[Predicate_IsKnownEconomist]()
580 | returns table
581 | as
582 | return
583 | select
584 | EntityID
585 | from
586 | Data.GetEntityProperties('knownFor_label')
587 | where
588 | Value in ('Economist', 'Economics', 'Finance')
589 |
590 |
591 | GO
592 | SET ANSI_NULLS ON
593 | GO
594 | SET QUOTED_IDENTIFIER ON
595 | GO
596 | CREATE function[Data].[Predicate_IsKnownForActivism]()
597 | returns table
598 | as
599 | return
600 | select
601 | EntityID
602 | from
603 | Data.GetEntityProperties('knownFor_label')
604 | where
605 | Value = 'Activism'
606 |
607 |
608 | GO
609 | SET ANSI_NULLS ON
610 | GO
611 | SET QUOTED_IDENTIFIER ON
612 | GO
613 | CREATE function[Data].[Predicate_IsKnownForAstronomyOrAstrophysics]()
614 | returns table
615 | as
616 | return
617 | select
618 | EntityID
619 | from
620 | Data.GetEntityProperties('knownFor_label')
621 | where
622 | Value in (
623 | 'Astronomy',
624 | 'Astrophysics',
625 | 'Dark matter',
626 | 'String theory',
627 | 'Superstring theory',
628 | 'Chaos theory'
629 | )
630 |
631 |
632 | GO
633 | SET ANSI_NULLS ON
634 | GO
635 | SET QUOTED_IDENTIFIER ON
636 | GO
637 | CREATE function[Data].[Predicate_IsKnownForBotanyOrBiology]()
638 | returns table
639 | as
640 | return
641 | select
642 | EntityID
643 | from
644 | Data.GetEntityProperties('knownFor_label')
645 | where
646 | Value in (
647 | 'Botany',
648 | 'Plant pathology',
649 | 'Flora',
650 | 'Zoology',
651 | 'Ornithology',
652 | 'Taxonomy (biology)',
653 | 'Entomology',
654 | 'Cell biology',
655 | 'Neuroscience'
656 | )
657 |
658 |
659 | GO
660 | SET ANSI_NULLS ON
661 | GO
662 | SET QUOTED_IDENTIFIER ON
663 | GO
664 | CREATE function[Data].[Predicate_IsKnownForCancerResearch]()
665 | returns table
666 | as
667 | return
668 | select
669 | EntityID
670 | from
671 | Data.GetEntityProperties('knownFor_label')
672 | where
673 | Value in ('Cancer research', 'Cancer')
674 |
675 |
676 | GO
677 | SET ANSI_NULLS ON
678 | GO
679 | SET QUOTED_IDENTIFIER ON
680 | GO
681 | CREATE function[Data].[Predicate_IsKnownForChemistry]()
682 | returns table
683 | as
684 | return
685 | select
686 | EntityID
687 | from
688 | Data.GetEntityProperties('knownFor_label')
689 | where
690 | Value in (
691 | 'Quantum chemistry',
692 | 'Organometallic chemistry',
693 | 'Stereochemistry',
694 | 'Periodic table'
695 | )
696 |
697 |
698 | GO
699 | SET ANSI_NULLS ON
700 | GO
701 | SET QUOTED_IDENTIFIER ON
702 | GO
703 | CREATE function[Data].[Predicate_IsKnownForComputerScience]()
704 | returns table
705 | as
706 | return
707 | select
708 | EntityID
709 | from
710 | Data.GetEntityProperties('knownFor_label')
711 | where
712 | Value in (
713 | 'Computer science',
714 | 'Ubiquitous computing',
715 | 'Human–computer interaction',
716 | 'Health informatics',
717 | 'Econometrics',
718 | 'Cryptanalysis',
719 | 'Information theory',
720 | 'Artificial intelligence',
721 | 'Computer security',
722 | 'Computational geometry',
723 | 'Robotics',
724 | 'Supercomputer'
725 | )
726 |
727 |
728 | GO
729 | SET ANSI_NULLS ON
730 | GO
731 | SET QUOTED_IDENTIFIER ON
732 | GO
733 | CREATE function[Data].[Predicate_IsKnownForFeminism]()
734 | returns table
735 | as
736 | return
737 | select
738 | EntityID
739 | from
740 | Data.GetEntityProperties('knownFor_label')
741 | where
742 | Value in ('Feminism', 'Women''s rights')
743 |
744 |
745 | GO
746 | SET ANSI_NULLS ON
747 | GO
748 | SET QUOTED_IDENTIFIER ON
749 | GO
750 | CREATE function[Data].[Predicate_IsKnownForGenetics]()
751 | returns table
752 | as
753 | return
754 | select
755 | EntityID
756 | from
757 | Data.GetEntityProperties('knownFor_label')
758 | where
759 | Value in (
760 | 'Embryogenesis',
761 | 'Genetics',
762 | 'Transduction (genetics)',
763 | 'DNA',
764 | 'Ancient DNA',
765 | 'DNA repair',
766 | 'Population genetics'
767 | )
768 |
769 |
770 | GO
771 | SET ANSI_NULLS ON
772 | GO
773 | SET QUOTED_IDENTIFIER ON
774 | GO
775 | CREATE function[Data].[Predicate_IsKnownForHumanRights]()
776 | returns table
777 | as
778 | return
779 | select
780 | EntityID
781 | from
782 | Data.GetEntityProperties('knownFor_label')
783 | where
784 | Value in ('Human rights', 'Human rights defender')
785 |
786 |
787 | GO
788 | SET ANSI_NULLS ON
789 | GO
790 | SET QUOTED_IDENTIFIER ON
791 | GO
792 | CREATE function[Data].[Predicate_IsKnownForInternet]()
793 | returns table
794 | as
795 | return
796 | select
797 | EntityID
798 | from
799 | Data.GetEntityProperties('knownFor_label')
800 | where
801 | Value in (
802 | 'Video blog',
803 | 'Blog',
804 | 'YouTube'
805 | )
806 |
807 |
808 | GO
809 | SET ANSI_NULLS ON
810 | GO
811 | SET QUOTED_IDENTIFIER ON
812 | GO
813 | CREATE function[Data].[Predicate_IsKnownForMathematic]()
814 | returns table
815 | as
816 | return
817 | select
818 | EntityID
819 | from
820 | Data.GetEntityProperties('knownFor_label')
821 | where
822 | Value in (
823 | 'Partial differential equation',
824 | 'Combinatorics',
825 | 'Functional analysis',
826 | 'Group theory',
827 | 'Differential geometry',
828 | 'Dynamical system',
829 | 'Dynamical systems theory',
830 | 'Topology',
831 | 'Finite element method',
832 | 'Mathematical analysis',
833 | 'Algebraic geometry',
834 | 'Analytic number theory',
835 | 'Systems theory',
836 | 'Graph theory',
837 | 'Game theory',
838 | 'Numerical analysis',
839 | 'Set theory',
840 | 'Statistics',
841 | 'Operations research',
842 | 'Nonlinear system',
843 | 'Geometric measure theory',
844 | 'Applied mathematics'
845 | )
846 |
847 |
848 | GO
849 | SET ANSI_NULLS ON
850 | GO
851 | SET QUOTED_IDENTIFIER ON
852 | GO
853 | CREATE function[Data].[Predicate_IsKnownForMedicine]()
854 | returns table
855 | as
856 | return
857 | select
858 | EntityID
859 | from
860 | Data.GetEntityProperties('knownFor_label')
861 | where
862 | Value in (
863 | 'Medicine',
864 | 'Immunology',
865 | 'Dermatology',
866 | 'Diabetes mellitus',
867 | 'Public health',
868 | 'Surgical pathology',
869 | 'Penicillin',
870 | 'Tuberculosis'
871 | )
872 |
873 |
874 | GO
875 | SET ANSI_NULLS ON
876 | GO
877 | SET QUOTED_IDENTIFIER ON
878 | GO
879 | CREATE function[Data].[Predicate_IsKnownForPhilanthropy]()
880 | returns table
881 | as
882 | return
883 | select
884 | EntityID
885 | from
886 | Data.GetEntityProperties('knownFor_label')
887 | where
888 | Value = 'Philanthropy'
889 |
890 |
891 | GO
892 | SET ANSI_NULLS ON
893 | GO
894 | SET QUOTED_IDENTIFIER ON
895 | GO
896 | CREATE function[Data].[Predicate_IsKnownForPhotography]()
897 | returns table
898 | as
899 | return
900 | select
901 | EntityID
902 | from
903 | Data.GetEntityProperties('knownFor_label')
904 | where
905 | Value in ('Photography', 'photography')
906 |
907 |
908 | GO
909 | SET ANSI_NULLS ON
910 | GO
911 | SET QUOTED_IDENTIFIER ON
912 | GO
913 | CREATE function[Data].[Predicate_IsKnownForPhysics]()
914 | returns table
915 | as
916 | return
917 | select
918 | EntityID
919 | from
920 | Data.GetEntityProperties('knownFor_label')
921 | where
922 | Value in (
923 | 'Nuclear magnetic resonance',
924 | 'Nuclear physics',
925 | 'High-temperature superconductivity',
926 | 'Quantum field theory',
927 | 'Mass spectrometry',
928 | 'Particle physics',
929 | 'Relative atomic mass',
930 | 'Nanotechnology',
931 | 'General relativity',
932 | 'X-ray crystallography',
933 | 'Phase transition',
934 | 'Fluid dynamics',
935 | 'Thermodynamics',
936 | 'Carbon nanotube',
937 | 'Plasma (physics)',
938 | 'Quantum mechanics',
939 | 'Electron',
940 | 'Gravitation',
941 | 'Cosmic ray',
942 | 'Ultracold atom',
943 | 'Supersymmetry',
944 | 'Theoretical physics',
945 | 'Thermoelectric effect',
946 | 'X-ray',
947 | 'Mathematical physics',
948 | 'Superconductivity',
949 | 'Statistical mechanics'
950 | )
951 |
952 |
953 | GO
954 | SET ANSI_NULLS ON
955 | GO
956 | SET QUOTED_IDENTIFIER ON
957 | GO
958 | CREATE function[Data].[Predicate_IsKnownInIndia]()
959 | returns table
960 | as
961 | return
962 | select
963 | EntityID
964 | from
965 | Data.GetEntityProperties('knownFor_label')
966 | where
967 | Value in ('Indian independence movement', 'India')
968 |
969 |
970 | GO
971 | SET ANSI_NULLS ON
972 | GO
973 | SET QUOTED_IDENTIFIER ON
974 | GO
975 | CREATE function[Data].[Predicate_IsLivingPerson]()
976 | returns table
977 | as
978 | return
979 | select
980 | EntityID
981 | from
982 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
983 | where
984 | (Value = 'LivingPeople')
985 |
986 | GO
987 | SET ANSI_NULLS ON
988 | GO
989 | SET QUOTED_IDENTIFIER ON
990 | GO
991 | CREATE function[Data].[Predicate_IsMale]()
992 | returns table
993 | as
994 | return
995 | select
996 | EntityID
997 | from
998 | Data.GetEntityProperties('gender_label')
999 | where
1000 | (Value = 'Male')
1001 |
1002 |
1003 | GO
1004 | SET ANSI_NULLS ON
1005 | GO
1006 | SET QUOTED_IDENTIFIER ON
1007 | GO
1008 | CREATE function[Data].[Predicate_IsMilitary]()
1009 | returns table
1010 | as
1011 | return
1012 | select
1013 | EntityID
1014 | from
1015 | Data.GetEntityProperties('militaryCommand')
1016 | union all
1017 | select
1018 | EntityID
1019 | from
1020 | Data.GetEntityProperties('militaryBranch_label')
1021 | union all
1022 | select
1023 | EntityID
1024 | from
1025 | Data.GetEntityProperties('militaryUnit_label')
1026 | union all
1027 | select
1028 | EntityID
1029 | from
1030 | Data.GetEntityProperties('militaryRank_label')
1031 | union all
1032 | select
1033 | EntityID
1034 | from
1035 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1036 | where
1037 | (Value = 'military person')
1038 |
1039 | GO
1040 | SET ANSI_NULLS ON
1041 | GO
1042 | SET QUOTED_IDENTIFIER ON
1043 | GO
1044 | CREATE function[Data].[Predicate_IsMinister]()
1045 | returns table
1046 | as
1047 | return
1048 | select
1049 | EntityID
1050 | from
1051 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1052 | where
1053 | (Value like 'Minister%')
1054 |
1055 | GO
1056 | SET ANSI_NULLS ON
1057 | GO
1058 | SET QUOTED_IDENTIFIER ON
1059 | GO
1060 | CREATE function[Data].[Predicate_IsModel]()
1061 | returns table
1062 | as
1063 | return
1064 | select
1065 | EntityID
1066 | from
1067 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1068 | where
1069 | (Value = 'model')
1070 |
1071 | GO
1072 | SET ANSI_NULLS ON
1073 | GO
1074 | SET QUOTED_IDENTIFIER ON
1075 | GO
1076 | CREATE function[Data].[Predicate_IsMonarch]()
1077 | returns table
1078 | as
1079 | return
1080 | select
1081 | EntityID
1082 | from
1083 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1084 | where
1085 | (Value in ('Monarch', 'monarch'))
1086 |
1087 | GO
1088 | SET ANSI_NULLS ON
1089 | GO
1090 | SET QUOTED_IDENTIFIER ON
1091 | GO
1092 | CREATE function[Data].[Predicate_IsMonarchist]()
1093 | returns table
1094 | as
1095 | return
1096 | select
1097 | EntityID
1098 | from
1099 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1100 | where
1101 | (Value like 'Monarchist%')
1102 |
1103 | GO
1104 | SET ANSI_NULLS ON
1105 | GO
1106 | SET QUOTED_IDENTIFIER ON
1107 | GO
1108 | CREATE function[Data].[Predicate_IsMotorsportRacer]()
1109 | returns table
1110 | as
1111 | return
1112 | select
1113 | EntityID
1114 | from
1115 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1116 | where
1117 | (Value = 'motorsport racer')
1118 |
1119 |
1120 | GO
1121 | SET ANSI_NULLS ON
1122 | GO
1123 | SET QUOTED_IDENTIFIER ON
1124 | GO
1125 | CREATE function[Data].[Predicate_IsMusician]()
1126 | returns table
1127 | as
1128 | return
1129 | select
1130 | EntityID
1131 | from
1132 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1133 | where
1134 | Value like '%Musician%'
1135 |
1136 |
1137 | GO
1138 | SET ANSI_NULLS ON
1139 | GO
1140 | SET QUOTED_IDENTIFIER ON
1141 | GO
1142 | CREATE function[Data].[Predicate_IsNoble]()
1143 | returns table
1144 | as
1145 | return
1146 | select
1147 | EntityID
1148 | from
1149 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
1150 | where
1151 | (Value = 'http://dbpedia.org/ontology/Noble')
1152 |
1153 | GO
1154 | SET ANSI_NULLS ON
1155 | GO
1156 | SET QUOTED_IDENTIFIER ON
1157 | GO
1158 | CREATE function[Data].[Predicate_IsOfficer]()
1159 | returns table
1160 | as
1161 | return
1162 | select
1163 | EntityID
1164 | from
1165 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1166 | where
1167 | Value like '%Officer%'
1168 |
1169 |
1170 | GO
1171 | SET ANSI_NULLS ON
1172 | GO
1173 | SET QUOTED_IDENTIFIER ON
1174 | GO
1175 | CREATE function[Data].[Predicate_IsOrganist]()
1176 | returns table
1177 | as
1178 | return
1179 | select
1180 | EntityID
1181 | from
1182 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1183 | where
1184 | Value like '%Organist%'
1185 |
1186 |
1187 | GO
1188 | SET ANSI_NULLS ON
1189 | GO
1190 | SET QUOTED_IDENTIFIER ON
1191 | GO
1192 | CREATE function[Data].[Predicate_IsPainter]()
1193 | returns table
1194 | as
1195 | return
1196 | select
1197 | EntityID
1198 | from
1199 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1200 | where
1201 | (Value in ('Painter', 'painter'))
1202 |
1203 | GO
1204 | SET ANSI_NULLS ON
1205 | GO
1206 | SET QUOTED_IDENTIFIER ON
1207 | GO
1208 | CREATE function[Data].[Predicate_IsPhilosopher]()
1209 | returns table
1210 | as
1211 | return
1212 | select
1213 | EntityID
1214 | from
1215 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1216 | where
1217 | (Value = 'philosopher')
1218 |
1219 | GO
1220 | SET ANSI_NULLS ON
1221 | GO
1222 | SET QUOTED_IDENTIFIER ON
1223 | GO
1224 |
1225 | CREATE function[Data].[Predicate_IsPoet]()
1226 | returns table
1227 | as
1228 | return
1229 | select
1230 | EntityID
1231 | from
1232 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
1233 | where
1234 | (Value = 'http://dbpedia.org/ontology/Poet')
1235 |
1236 | GO
1237 | SET ANSI_NULLS ON
1238 | GO
1239 | SET QUOTED_IDENTIFIER ON
1240 | GO
1241 | CREATE function[Data].[Predicate_IsPolitician]()
1242 | returns table
1243 | as
1244 | return
1245 | select
1246 | EntityID
1247 | from
1248 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1249 | where
1250 | Value like '%Politician%'
1251 |
1252 |
1253 | GO
1254 | SET ANSI_NULLS ON
1255 | GO
1256 | SET QUOTED_IDENTIFIER ON
1257 | GO
1258 |
1259 | CREATE function[Data].[Predicate_IsPope]()
1260 | returns table
1261 | as
1262 | return
1263 | select
1264 | EntityID
1265 | from
1266 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
1267 | where
1268 | (Value = 'http://dbpedia.org/ontology/Pope')
1269 |
1270 | GO
1271 | SET ANSI_NULLS ON
1272 | GO
1273 | SET QUOTED_IDENTIFIER ON
1274 | GO
1275 | CREATE function[Data].[Predicate_IsPracticingMartialArts]()
1276 | returns table
1277 | as
1278 | return
1279 | select
1280 | EntityID
1281 | from
1282 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1283 | where
1284 | Value like '%Practitioners%'
1285 |
1286 |
1287 | GO
1288 | SET ANSI_NULLS ON
1289 | GO
1290 | SET QUOTED_IDENTIFIER ON
1291 | GO
1292 | CREATE function[Data].[Predicate_IsPresident]()
1293 | returns table
1294 | as
1295 | return
1296 | select
1297 | EntityID
1298 | from
1299 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1300 | where
1301 | (Value like '%President%')
1302 |
1303 | GO
1304 | SET ANSI_NULLS ON
1305 | GO
1306 | SET QUOTED_IDENTIFIER ON
1307 | GO
1308 | CREATE function[Data].[Predicate_IsPrimeMinister]()
1309 | returns table
1310 | as
1311 | return
1312 | select
1313 | EntityID
1314 | from
1315 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1316 | where
1317 | (Value like 'PrimeMinister%')
1318 |
1319 | GO
1320 | SET ANSI_NULLS ON
1321 | GO
1322 | SET QUOTED_IDENTIFIER ON
1323 | GO
1324 | CREATE function[Data].[Predicate_IsRacingDriver]()
1325 | returns table
1326 | as
1327 | return
1328 | select
1329 | EntityID
1330 | from
1331 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1332 | where
1333 | (Value = 'racing driver')
1334 |
1335 |
1336 | GO
1337 | SET ANSI_NULLS ON
1338 | GO
1339 | SET QUOTED_IDENTIFIER ON
1340 | GO
1341 | CREATE function[Data].[Predicate_IsReligious]()
1342 | returns table
1343 | as
1344 | return
1345 | select
1346 | EntityID
1347 | from
1348 | Data.GetEntityProperties('religion_label')
1349 | group by
1350 | EntityID
1351 |
1352 |
1353 | GO
1354 | SET ANSI_NULLS ON
1355 | GO
1356 | SET QUOTED_IDENTIFIER ON
1357 | GO
1358 | CREATE function[Data].[Predicate_IsRugbyPlayer]()
1359 | returns table
1360 | as
1361 | return
1362 | select
1363 | EntityID
1364 | from
1365 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1366 | where
1367 | (Value = 'rugby player')
1368 |
1369 |
1370 | GO
1371 | SET ANSI_NULLS ON
1372 | GO
1373 | SET QUOTED_IDENTIFIER ON
1374 | GO
1375 | CREATE function[Data].[Predicate_IsSaint]()
1376 | returns table
1377 | as
1378 | return
1379 | select
1380 | EntityID
1381 | from
1382 | Data.GetEntityProperties('22-rdf-syntax-ns#type')
1383 | where
1384 | (Value = 'http://dbpedia.org/ontology/Saint')
1385 |
1386 | GO
1387 | SET ANSI_NULLS ON
1388 | GO
1389 | SET QUOTED_IDENTIFIER ON
1390 | GO
1391 | CREATE function[Data].[Predicate_IsScientist]()
1392 | returns table
1393 | as
1394 | return
1395 | select
1396 | EntityID
1397 | from
1398 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1399 | where
1400 | (Value like '%Scientist%')
1401 |
1402 | GO
1403 | SET ANSI_NULLS ON
1404 | GO
1405 | SET QUOTED_IDENTIFIER ON
1406 | GO
1407 | CREATE function[Data].[Predicate_IsSinger]()
1408 | returns table
1409 | as
1410 | return
1411 | select
1412 | EntityID
1413 | from
1414 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1415 | where
1416 | (Value like '%Singer%')
1417 |
1418 | GO
1419 | SET ANSI_NULLS ON
1420 | GO
1421 | SET QUOTED_IDENTIFIER ON
1422 | GO
1423 | CREATE function[Data].[Predicate_IsSoapCharacter]()
1424 | returns table
1425 | as
1426 | return
1427 | select
1428 | EntityID
1429 | from
1430 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1431 | where
1432 | (Value = 'soap character')
1433 |
1434 | GO
1435 | SET ANSI_NULLS ON
1436 | GO
1437 | SET QUOTED_IDENTIFIER ON
1438 | GO
1439 | CREATE function[Data].[Predicate_IsSportManager]()
1440 | returns table
1441 | as
1442 | return
1443 | select
1444 | EntityID
1445 | from
1446 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1447 | where
1448 | (Value in ('sports manager', 'soccer manager'))
1449 |
1450 | GO
1451 | SET ANSI_NULLS ON
1452 | GO
1453 | SET QUOTED_IDENTIFIER ON
1454 | GO
1455 | CREATE function[Data].[Predicate_IsSwimmer]()
1456 | returns table
1457 | as
1458 | return
1459 | select
1460 | EntityID
1461 | from
1462 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1463 | where
1464 | (Value = 'swimmer')
1465 |
1466 |
1467 | GO
1468 | SET ANSI_NULLS ON
1469 | GO
1470 | SET QUOTED_IDENTIFIER ON
1471 | GO
1472 |
1473 | CREATE function[Data].[Predicate_IsTall]()
1474 | returns table
1475 | as
1476 | return
1477 | select
1478 | EntityID
1479 | from
1480 | Data.GetEntityProperties('height')
1481 | cross apply
1482 | (
1483 | select try_cast(Value as money) DecimalValue
1484 | ) V
1485 | where
1486 | (iif(DecimalValue < 3, DecimalValue * 100, DecimalValue) >= 185)
1487 |
1488 | GO
1489 | SET ANSI_NULLS ON
1490 | GO
1491 | SET QUOTED_IDENTIFIER ON
1492 | GO
1493 | CREATE function[Data].[Predicate_IsTelevisionTalkShowHosts]()
1494 | returns table
1495 | as
1496 | return
1497 | select
1498 | EntityID
1499 | from
1500 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1501 | where
1502 | (Value like '%TelevisionTalkShowHosts%')
1503 |
1504 | GO
1505 | SET ANSI_NULLS ON
1506 | GO
1507 | SET QUOTED_IDENTIFIER ON
1508 | GO
1509 | CREATE function[Data].[Predicate_IsWorkingOnFriday]()
1510 | returns table
1511 | as
1512 | return
1513 | select
1514 | EntityID
1515 | from
1516 | Data.GetEntityProperties('OpenOnFriday')
1517 | where
1518 | (Value in (N'כן', 'yes', 'true', '1'))
1519 |
1520 |
1521 |
1522 | GO
1523 | SET ANSI_NULLS ON
1524 | GO
1525 | SET QUOTED_IDENTIFIER ON
1526 | GO
1527 | CREATE function[Data].[Predicate_IsWorkingOnSaturday]()
1528 | returns table
1529 | as
1530 | return
1531 | select
1532 | EntityID
1533 | from
1534 | Data.GetEntityProperties('OpenOnSaturday')
1535 | where
1536 | (Value in (N'כן', 'yes', 'true', '1'))
1537 |
1538 |
1539 | GO
1540 | SET ANSI_NULLS ON
1541 | GO
1542 | SET QUOTED_IDENTIFIER ON
1543 | GO
1544 | CREATE function[Data].[Predicate_IsWriter]()
1545 | returns table
1546 | as
1547 | return
1548 | select
1549 | EntityID
1550 | from
1551 | Data.GetEntityProperties('22-rdf-syntax-ns#type_label')
1552 | where
1553 | (Value = 'writer')
1554 |
1555 | GO
1556 | SET ANSI_NULLS ON
1557 | GO
1558 | SET QUOTED_IDENTIFIER ON
1559 | GO
1560 | CREATE function[Data].[Predicate_Location]()
1561 | returns table
1562 | as
1563 | return
1564 | select
1565 | EntityID
1566 | from
1567 | Data.GetEntityProperties('nationality_label')
1568 | union all
1569 | select
1570 | EntityID
1571 | from
1572 | Data.GetEntityProperties('birthPlace_label')
1573 |
1574 | GO
1575 | SET ANSI_NULLS ON
1576 | GO
1577 | SET QUOTED_IDENTIFIER ON
1578 | GO
1579 | CREATE function[Data].[Predicate_Sex]()
1580 | returns table
1581 | as
1582 | return
1583 | select
1584 | EntityID
1585 | from
1586 | Data.GetEntityProperties('gender_label')
1587 |
1588 |
1589 | GO
1590 | SET ANSI_NULLS ON
1591 | GO
1592 | SET QUOTED_IDENTIFIER ON
1593 | GO
1594 | CREATE function[Data].[Predicate_WasBornInAfrica]()
1595 | returns table
1596 | as
1597 | return
1598 | select
1599 | EntityID
1600 | from
1601 | Data.Predicate
1602 | where
1603 | --PredicateID in (Data.GetPredicateID('WasBornInBrazil'), Data.GetPredicateID('WasBornInArgentina'));
1604 | 1 = 0
1605 |
1606 | GO
1607 | SET ANSI_NULLS ON
1608 | GO
1609 | SET QUOTED_IDENTIFIER ON
1610 | GO
1611 | CREATE function[Data].[Predicate_WasBornInArgentina]()
1612 | returns table
1613 | as
1614 | return
1615 | select
1616 | EntityID
1617 | from
1618 | Data.GetEntityProperties('birthPlace_label')
1619 | where
1620 | Value = 'Argentina'
1621 |
1622 |
1623 | GO
1624 | SET ANSI_NULLS ON
1625 | GO
1626 | SET QUOTED_IDENTIFIER ON
1627 | GO
1628 | CREATE function[Data].[Predicate_WasBornInAustraliaOrNewZeland]()
1629 | returns table
1630 | as
1631 | return
1632 | select
1633 | EntityID
1634 | from
1635 | Data.GetEntityProperties('birthPlace_label')
1636 | where
1637 | Value in (
1638 | 'Australia',
1639 | 'Victoria (Australia)',
1640 | 'Western Australia',
1641 | 'South Australia',
1642 | 'New Zealand'
1643 |
1644 | )
1645 |
1646 |
1647 | GO
1648 | SET ANSI_NULLS ON
1649 | GO
1650 | SET QUOTED_IDENTIFIER ON
1651 | GO
1652 | CREATE function[Data].[Predicate_WasBornInBrazil]()
1653 | returns table
1654 | as
1655 | return
1656 | select
1657 | EntityID
1658 | from
1659 | Data.GetEntityProperties('birthPlace_label')
1660 | where
1661 | Value = 'Brazil'
1662 |
1663 |
1664 | GO
1665 | SET ANSI_NULLS ON
1666 | GO
1667 | SET QUOTED_IDENTIFIER ON
1668 | GO
1669 | CREATE function[Data].[Predicate_WasBornInCanada]()
1670 | returns table
1671 | as
1672 | return
1673 | select
1674 | EntityID
1675 | from
1676 | Data.GetEntityProperties('birthPlace_label')
1677 | where
1678 | Value = 'Canada'
1679 |
1680 |
1681 | GO
1682 | SET ANSI_NULLS ON
1683 | GO
1684 | SET QUOTED_IDENTIFIER ON
1685 | GO
1686 | CREATE function[Data].[Predicate_WasBornInChina]()
1687 | returns table
1688 | as
1689 | return
1690 | select
1691 | EntityID
1692 | from
1693 | Data.GetEntityProperties('birthPlace_label')
1694 | where
1695 | Value in (
1696 | 'China',
1697 | 'Republic of China (1912GÇô49)',
1698 | 'Mainland China'
1699 | )
1700 |
1701 |
1702 | GO
1703 | SET ANSI_NULLS ON
1704 | GO
1705 | SET QUOTED_IDENTIFIER ON
1706 | GO
1707 | CREATE function[Data].[Predicate_WasBornInFarEast]()
1708 | returns table
1709 | as
1710 | return
1711 | select
1712 | EntityID
1713 | from
1714 | Data.Predicate
1715 | where
1716 | PredicateID in
1717 | (
1718 | Data.GetPredicateID('WasBornInJapan'),
1719 | Data.GetPredicateID('WasBornInKorea'),
1720 | Data.GetPredicateID('WasBornInChina')
1721 | );
1722 |
1723 |
1724 | GO
1725 | SET ANSI_NULLS ON
1726 | GO
1727 | SET QUOTED_IDENTIFIER ON
1728 | GO
1729 | CREATE function[Data].[Predicate_WasBornInFrance]()
1730 | returns table
1731 | as
1732 | return
1733 | select
1734 | EntityID
1735 | from
1736 | Data.GetEntityProperties('birthPlace_label')
1737 | where
1738 | Value = 'France'
1739 |
1740 |
1741 | GO
1742 | SET ANSI_NULLS ON
1743 | GO
1744 | SET QUOTED_IDENTIFIER ON
1745 | GO
1746 | CREATE function[Data].[Predicate_WasBornInGermany]()
1747 | returns table
1748 | as
1749 | return
1750 | select
1751 | EntityID
1752 | from
1753 | Data.GetEntityProperties('birthPlace_label')
1754 | where
1755 | Value in
1756 | (
1757 | 'Germany',
1758 | 'West Germany',
1759 | 'East Germany'
1760 | )
1761 |
1762 |
1763 | GO
1764 | SET ANSI_NULLS ON
1765 | GO
1766 | SET QUOTED_IDENTIFIER ON
1767 | GO
1768 | CREATE function[Data].[Predicate_WasBornInIndia]()
1769 | returns table
1770 | as
1771 | return
1772 | select
1773 | EntityID
1774 | from
1775 | Data.GetEntityProperties('birthPlace_label')
1776 | where
1777 | Value in ('India', 'Presidencies and provinces of British India')
1778 |
1779 |
1780 | GO
1781 | SET ANSI_NULLS ON
1782 | GO
1783 | SET QUOTED_IDENTIFIER ON
1784 | GO
1785 | CREATE function[Data].[Predicate_WasBornInIsrael]()
1786 | returns table
1787 | as
1788 | return
1789 | select
1790 | EntityID
1791 | from
1792 | Data.GetEntityProperties('birthPlace_label')
1793 | where
1794 | Value = 'Israel'
1795 |
1796 |
1797 | GO
1798 | SET ANSI_NULLS ON
1799 | GO
1800 | SET QUOTED_IDENTIFIER ON
1801 | GO
1802 | CREATE function[Data].[Predicate_WasBornInItaly]()
1803 | returns table
1804 | as
1805 | return
1806 | select
1807 | EntityID
1808 | from
1809 | Data.GetEntityProperties('birthPlace_label')
1810 | where
1811 | Value = 'Italy'
1812 |
1813 |
1814 | GO
1815 | SET ANSI_NULLS ON
1816 | GO
1817 | SET QUOTED_IDENTIFIER ON
1818 | GO
1819 | CREATE function[Data].[Predicate_WasBornInJapan]()
1820 | returns table
1821 | as
1822 | return
1823 | select
1824 | EntityID
1825 | from
1826 | Data.GetEntityProperties('birthPlace_label')
1827 | where
1828 | Value = 'Japan'
1829 |
1830 |
1831 | GO
1832 | SET ANSI_NULLS ON
1833 | GO
1834 | SET QUOTED_IDENTIFIER ON
1835 | GO
1836 | CREATE function[Data].[Predicate_WasBornInKorea]()
1837 | returns table
1838 | as
1839 | return
1840 | select
1841 | EntityID
1842 | from
1843 | Data.GetEntityProperties('birthPlace_label')
1844 | where
1845 | Value in (
1846 | 'South Korea',
1847 | 'North Korea',
1848 | 'Korea'
1849 | )
1850 |
1851 |
1852 | GO
1853 | SET ANSI_NULLS ON
1854 | GO
1855 | SET QUOTED_IDENTIFIER ON
1856 | GO
1857 | CREATE function[Data].[Predicate_WasBornInMidleEast]()
1858 | returns table
1859 | as
1860 | return
1861 | select
1862 | EntityID
1863 | from
1864 | Data.Predicate
1865 | where
1866 | PredicateID in
1867 | (
1868 | Data.GetPredicateID('WasBornInIsrael'),
1869 | Data.GetPredicateID('WasBornInTurkey')
1870 | );
1871 |
1872 |
1873 | GO
1874 | SET ANSI_NULLS ON
1875 | GO
1876 | SET QUOTED_IDENTIFIER ON
1877 | GO
1878 | CREATE function[Data].[Predicate_WasBornInNetherlands]()
1879 | returns table
1880 | as
1881 | return
1882 | select
1883 | EntityID
1884 | from
1885 | Data.GetEntityProperties('birthPlace_label')
1886 | where
1887 | Value = 'Netherlands'
1888 |
1889 |
1890 | GO
1891 | SET ANSI_NULLS ON
1892 | GO
1893 | SET QUOTED_IDENTIFIER ON
1894 | GO
1895 | CREATE function[Data].[Predicate_WasBornInNorthAmerica]()
1896 | returns table
1897 | as
1898 | return
1899 | select
1900 | EntityID
1901 | from
1902 | Data.Predicate
1903 | where
1904 | PredicateID in (Data.GetPredicateID('WasBornInUSA'), Data.GetPredicateID('WasBornInCanada'));
1905 |
1906 | GO
1907 | SET ANSI_NULLS ON
1908 | GO
1909 | SET QUOTED_IDENTIFIER ON
1910 | GO
1911 | CREATE function[Data].[Predicate_WasBornInPoland]()
1912 | returns table
1913 | as
1914 | return
1915 | select
1916 | EntityID
1917 | from
1918 | Data.GetEntityProperties('birthPlace_label')
1919 | where
1920 | Value = 'Poland'
1921 |
1922 |
1923 | GO
1924 | SET ANSI_NULLS ON
1925 | GO
1926 | SET QUOTED_IDENTIFIER ON
1927 | GO
1928 | CREATE function[Data].[Predicate_WasBornInRussia]()
1929 | returns table
1930 | as
1931 | return
1932 | select
1933 | EntityID
1934 | from
1935 | Data.GetEntityProperties('birthPlace_label')
1936 | where
1937 | Value in (
1938 | 'Russia',
1939 | 'Russian Empire'
1940 | )
1941 |
1942 |
1943 | GO
1944 | SET ANSI_NULLS ON
1945 | GO
1946 | SET QUOTED_IDENTIFIER ON
1947 | GO
1948 | CREATE function[Data].[Predicate_WasBornInRussiaOrInSovietUnion]()
1949 | returns table
1950 | as
1951 | return
1952 | select
1953 | EntityID
1954 | from
1955 | Data.GetEntityProperties('birthPlace_label')
1956 | where
1957 | Value in (
1958 | 'Russia',
1959 | 'Russian Empire',
1960 | 'Soviet Union',
1961 | 'Russian Soviet Federative Socialist Republic',
1962 | 'Ukrainian Soviet Socialist Republic',
1963 | 'Byelorussian Soviet Socialist Republic',
1964 | 'Georgian Soviet Socialist Republic',
1965 | 'Kazakh Soviet Socialist Republic',
1966 | 'Latvian Soviet Socialist Republic',
1967 | 'Lithuanian Soviet Socialist Republic',
1968 | 'Azerbaijan Soviet Socialist Republic',
1969 | 'Uzbek Soviet Socialist Republic',
1970 | 'Armenian Soviet Socialist Republic',
1971 | 'Moldavian Soviet Socialist Republic',
1972 | 'Kirghiz Soviet Socialist Republic',
1973 | 'Tajik Soviet Socialist Republic',
1974 | 'Turkmen Soviet Socialist Republic',
1975 | 'Abkhaz Autonomous Soviet Socialist Republic',
1976 | 'Estonian Soviet Socialist Republic',
1977 | 'Dagestan Autonomous Soviet Socialist Republic',
1978 | 'ChechenGÇôIngush Autonomous Soviet Socialist Republic',
1979 | 'Chuvash Autonomous Soviet Socialist Republic',
1980 | 'Tatar Autonomous Soviet Socialist Republic',
1981 | 'Nakhchyvan Autonomous Soviet Socialist Republic',
1982 | 'North Ossetian Autonomous Soviet Socialist Republic',
1983 | 'Bashkir Autonomous Soviet Socialist Republic',
1984 | 'Mordovian Autonomous Soviet Socialist Republic',
1985 | 'Kabardino-Balkar Autonomous Soviet Socialist Republic',
1986 | 'Mari Autonomous Soviet Socialist Republic',
1987 | 'Kalmyk Autonomous Soviet Socialist Republic',
1988 | 'Udmurt Autonomous Soviet Socialist Republic',
1989 | 'Karelian Autonomous Soviet Socialist Republic',
1990 | 'Adjar Autonomous Soviet Socialist Republic',
1991 | 'Komi Autonomous Soviet Socialist Republic',
1992 | 'Yakut Autonomous Soviet Socialist Republic'
1993 | )
1994 |
1995 |
1996 | GO
1997 | SET ANSI_NULLS ON
1998 | GO
1999 | SET QUOTED_IDENTIFIER ON
2000 | GO
2001 | CREATE function[Data].[Predicate_WasBornInSouthAmerica]()
2002 | returns table
2003 | as
2004 | return
2005 | select
2006 | EntityID
2007 | from
2008 | Data.Predicate
2009 | where
2010 | PredicateID in (Data.GetPredicateID('WasBornInBrazil'), Data.GetPredicateID('WasBornInArgentina'));
2011 |
2012 |
2013 |
2014 |
2015 |
2016 |
2017 | GO
2018 | SET ANSI_NULLS ON
2019 | GO
2020 | SET QUOTED_IDENTIFIER ON
2021 | GO
2022 | CREATE function[Data].[Predicate_WasBornInSovietUnion]()
2023 | returns table
2024 | as
2025 | return
2026 | select
2027 | EntityID
2028 | from
2029 | Data.GetEntityProperties('birthPlace_label')
2030 | where
2031 | Value in (
2032 | 'Soviet Union',
2033 | 'Russian Soviet Federative Socialist Republic',
2034 | 'Ukrainian Soviet Socialist Republic',
2035 | 'Byelorussian Soviet Socialist Republic',
2036 | 'Georgian Soviet Socialist Republic',
2037 | 'Kazakh Soviet Socialist Republic',
2038 | 'Latvian Soviet Socialist Republic',
2039 | 'Lithuanian Soviet Socialist Republic',
2040 | 'Azerbaijan Soviet Socialist Republic',
2041 | 'Uzbek Soviet Socialist Republic',
2042 | 'Armenian Soviet Socialist Republic',
2043 | 'Moldavian Soviet Socialist Republic',
2044 | 'Kirghiz Soviet Socialist Republic',
2045 | 'Tajik Soviet Socialist Republic',
2046 | 'Turkmen Soviet Socialist Republic',
2047 | 'Abkhaz Autonomous Soviet Socialist Republic',
2048 | 'Estonian Soviet Socialist Republic',
2049 | 'Dagestan Autonomous Soviet Socialist Republic',
2050 | 'ChechenGÇôIngush Autonomous Soviet Socialist Republic',
2051 | 'Chuvash Autonomous Soviet Socialist Republic',
2052 | 'Tatar Autonomous Soviet Socialist Republic',
2053 | 'Nakhchyvan Autonomous Soviet Socialist Republic',
2054 | 'North Ossetian Autonomous Soviet Socialist Republic',
2055 | 'Bashkir Autonomous Soviet Socialist Republic',
2056 | 'Mordovian Autonomous Soviet Socialist Republic',
2057 | 'Kabardino-Balkar Autonomous Soviet Socialist Republic',
2058 | 'Mari Autonomous Soviet Socialist Republic',
2059 | 'Kalmyk Autonomous Soviet Socialist Republic',
2060 | 'Udmurt Autonomous Soviet Socialist Republic',
2061 | 'Karelian Autonomous Soviet Socialist Republic',
2062 | 'Adjar Autonomous Soviet Socialist Republic',
2063 | 'Komi Autonomous Soviet Socialist Republic',
2064 | 'Yakut Autonomous Soviet Socialist Republic'
2065 | )
2066 |
2067 |
2068 | GO
2069 | SET ANSI_NULLS ON
2070 | GO
2071 | SET QUOTED_IDENTIFIER ON
2072 | GO
2073 | CREATE function[Data].[Predicate_WasBornInSpain]()
2074 | returns table
2075 | as
2076 | return
2077 | select
2078 | EntityID
2079 | from
2080 | Data.GetEntityProperties('birthPlace_label')
2081 | where
2082 | Value = 'Spain'
2083 |
2084 |
2085 | GO
2086 | SET ANSI_NULLS ON
2087 | GO
2088 | SET QUOTED_IDENTIFIER ON
2089 | GO
2090 | CREATE function[Data].[Predicate_WasBornInSweden]()
2091 | returns table
2092 | as
2093 | return
2094 | select
2095 | EntityID
2096 | from
2097 | Data.GetEntityProperties('birthPlace_label')
2098 | where
2099 | Value = 'Sweden'
2100 |
2101 |
2102 | GO
2103 | SET ANSI_NULLS ON
2104 | GO
2105 | SET QUOTED_IDENTIFIER ON
2106 | GO
2107 | CREATE function[Data].[Predicate_WasBornInTurkey]()
2108 | returns table
2109 | as
2110 | return
2111 | select
2112 | EntityID
2113 | from
2114 | Data.GetEntityProperties('birthPlace_label')
2115 | where
2116 | Value = 'Turkey'
2117 |
2118 |
2119 | GO
2120 | SET ANSI_NULLS ON
2121 | GO
2122 | SET QUOTED_IDENTIFIER ON
2123 | GO
2124 | CREATE function[Data].[Predicate_WasBornInUnitedKingdomOrIreland]()
2125 | returns table
2126 | as
2127 | return
2128 | select
2129 | EntityID
2130 | from
2131 | Data.GetEntityProperties('birthPlace_label')
2132 | where
2133 | Value in (
2134 | 'United Kingdom',
2135 | 'United Kingdom of Great Britain and Ireland',
2136 | 'England',
2137 | 'Scotland',
2138 | 'Ireland',
2139 | 'Republic of Ireland',
2140 | 'Northern Ireland'
2141 | )
2142 |
2143 |
2144 | GO
2145 | SET ANSI_NULLS ON
2146 | GO
2147 | SET QUOTED_IDENTIFIER ON
2148 | GO
2149 | CREATE function[Data].[Predicate_WasBornInUSA]()
2150 | returns table
2151 | as
2152 | return
2153 | select
2154 | EntityID
2155 | from
2156 | Data.GetEntityProperties('birthPlace_label')
2157 | where
2158 | Value = 'United States'
2159 |
2160 |
2161 | GO
2162 | SET ANSI_NULLS ON
2163 | GO
2164 | SET QUOTED_IDENTIFIER ON
2165 | GO
2166 | CREATE function[Data].[Predicate_WasBornInWesternMiddleOrNorthEurope]()
2167 | returns table
2168 | as
2169 | return
2170 | select
2171 | EntityID
2172 | from
2173 | Data.Predicate
2174 | where
2175 | PredicateID in
2176 | (
2177 | Data.GetPredicateID('WasBornInUnitedKingdomOrIreland'),
2178 | Data.GetPredicateID('WasBornInGermany'),
2179 | Data.GetPredicateID('WasBornInFrance'),
2180 | Data.GetPredicateID('WasBornInItaly'),
2181 | Data.GetPredicateID('WasBornInSpain'),
2182 | Data.GetPredicateID('WasBornInSweden'),
2183 | Data.GetPredicateID('WasBornInNetherlands'),
2184 | Data.GetPredicateID('WasBornInPoland')
2185 | );
2186 |
--------------------------------------------------------------------------------
/SQL/Persons/predicates.sql:
--------------------------------------------------------------------------------
1 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/2/', N'IsTall', N'Data.Predicate_IsTall()', 0, NULL, 0, 0)
2 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/3/', N'HasAwards', N'Data.Predicate_HasAwards()', 0, NULL, 0, 0)
3 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/4/', N'IsPolitician', N'Data.Predicate_IsPolitician()', 0, NULL, 0, 0)
4 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/4/1/', N'IsPresident', N'Data.Predicate_IsPresident()', 0, NULL, 0, 0)
5 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/4/3/', N'IsMinister', N'Data.Predicate_IsMinister()', 0, NULL, 0, 0)
6 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/4/3/1/', N'IsPrimeMinister', N'Data.Predicate_IsPrimeMinister()', 0, NULL, 0, 0)
7 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/4/4/', N'IsMonarchist', N'Data.Predicate_IsMonarchist()', 0, NULL, 0, 0)
8 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/5/', N'IsReligious', N'Data.Predicate_IsReligious()', 0, NULL, 0, 0)
9 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/6/', N'IsMilitary', N'Data.Predicate_IsMilitary() ', 0, NULL, 0, 0)
10 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/6/1/', N'IsOfficer', N'Data.Predicate_IsOfficer()', 0, NULL, 0, 0)
11 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/8/', N'IsFoodServingService', N'Data.Predicate_IsFoodServingService()', 1, NULL, 0, 0)
12 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/8/2/', N'HasChef', N'Data.Predicate_HasChef()', 0, NULL, 0, 0)
13 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/8/11/1/', N'IsWorkingOnFriday', N'Data.Predicate_IsWorkingOnFriday()', 0, NULL, 0, 0)
14 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/8/11/2/', N'IsWorkingOnSaturday', N'Data.Predicate_IsWorkingOnSaturday()', 0, NULL, 0, 0)
15 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/9/', N'IsArtist', N'Data.Predicate_IsArtist()', 0, NULL, 0, 0)
16 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/10/', N'IsWriter', N'Data.Predicate_IsWriter()', 0, NULL, 0, 0)
17 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/', N'IsScientist', N'Data.Predicate_IsScientist()', 0, NULL, 0, 0)
18 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/1/', N'IsKnownForAstronomyOrAstrophysics', N'Data.Predicate_IsKnownForAstronomyOrAstrophysics()', 0, NULL, 0, 0)
19 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/2/', N'IsKnownForBotanyOrBiology', N'Data.Predicate_IsKnownForBotanyOrBiology()', 0, NULL, 0, 0)
20 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/3/', N'IsKnownForCancerResearch', N'Data.Predicate_IsKnownForCancerResearch()', 0, NULL, 0, 0)
21 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/4/', N'IsKnownForChemistry', N'Data.Predicate_IsKnownForChemistry()', 0, NULL, 0, 0)
22 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/5/', N'IsKnownForComputerScience', N'Data.Predicate_IsKnownForComputerScience()', 0, NULL, 0, 0)
23 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/6/', N'IsKnownForGenetics', N'Data.Predicate_IsKnownForGenetics()', 0, NULL, 0, 0)
24 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/7/', N'IsKnownForMathematic', N'Data.Predicate_IsKnownForMathematic()', 0, NULL, 0, 0)
25 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/8/', N'IsKnownForMedicine', N'Data.Predicate_IsKnownForMedicine()', 0, NULL, 0, 0)
26 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/11/9/', N'IsKnownForPhysics', N'Data.Predicate_IsKnownForPhysics()', 0, NULL, 0, 0)
27 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/12/', N'IsFictionalCharacter', N'Data.Predicate_IsFictionalCharacter()', 0, NULL, 0, 0)
28 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/13/', N'IsActor', N'Data.Predicate_IsActor()', 0, NULL, 0, 0)
29 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/14/', N'IsNoble', N'Data.Predicate_IsNoble()', 0, NULL, 0, 0)
30 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/15/', N'IsSaint', N'Data.Predicate_IsSaint()', 0, NULL, 0, 0)
31 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/16/', N'IsMonarch', N'Data.Predicate_IsMonarch()', 0, NULL, 0, 0)
32 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/17/', N'IsPainter', N'Data.Predicate_IsPainter()', 0, NULL, 0, 0)
33 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/18/', N'IsArchitect', N'Data.Predicate_IsArchitect()', 0, NULL, 0, 0)
34 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/19/', N'IsSoapCharacter', N'Data.Predicate_IsSoapCharacter()', 0, NULL, 0, 0)
35 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/20/', N'IsCriminal', N'Data.Predicate_IsCriminal()', 0, NULL, 0, 0)
36 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/22/', N'IsBeautyQueen', N'Data.Predicate_IsBeautyQueen()', 0, NULL, 0, 0)
37 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/24/', N'IsPhilosopher', N'Data.Predicate_IsPhilosopher()', 0, NULL, 0, 0)
38 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/25/', N'IsJournalist', N'Data.Predicate_IsJournalist()', 0, NULL, 0, 0)
39 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/27/', N'IsComedian', N'Data.Predicate_IsComedian()', 0, NULL, 0, 0)
40 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/28/', N'IsBusinessPerson', N'Data.Predicate_IsBusinessPerson()', 0, NULL, 0, 0)
41 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/29/', N'IsHistorian', N'Data.Predicate_IsHistorian()', 0, NULL, 0, 0)
42 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/30/', N'IsAstronaut', N'Data.Predicate_IsAstronaut()', 0, NULL, 0, 0)
43 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/31/', N'IsPoet', N'Data.Predicate_IsPoet()', 0, NULL, 0, 0)
44 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/32/', N'IsPope', N'Data.Predicate_IsPope()', 0, NULL, 0, 0)
45 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/42/', N'IsSinger', N'Data.Predicate_IsSinger()', 0, NULL, 0, 0)
46 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/1/', N'IsKnownForPhilanthropy', N'Data.Predicate_IsKnownForPhilanthropy()', 0, NULL, 0, 0)
47 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/2/', N'IsKnownForActivism', N'Data.Predicate_IsKnownForActivism()', 0, NULL, 0, 0)
48 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/5/', N'IsKnownForHumanRights', N'Data.Predicate_IsKnownForHumanRights()', 0, NULL, 0, 0)
49 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/7/', N'IsKnownForPhotography', N'Data.Predicate_IsKnownForPhotography()', 0, NULL, 0, 0)
50 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/8/', N'IsKnownEconomist', N'Data.Predicate_IsKnownEconomist()', 0, NULL, 0, 0)
51 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/9/', N'IsKnownForFeminism', N'Data.Predicate_IsKnownForFeminism()', 0, NULL, 0, 0)
52 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/43/15/', N'IsKnownForInternet', N'Data.Predicate_IsKnownForInternet()', 0, NULL, 0, 0)
53 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/44/1/', N'HasBrownHairs', N'Data.Predicate_HasBrownHairs()', 0, NULL, 0, 0)
54 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/44/2/', N'HasReddishHairs', N'Data.Predicate_HasReddishHairs()', 0, NULL, 0, 0)
55 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/44/3/', N'HasBlackHairs', N'Data.Predicate_HasBlackHairs()', 0, NULL, 0, 0)
56 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/44/4/', N'HasLightHairs', N'Data.Predicate_HasLightHairs()', 0, NULL, 0, 0)
57 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/45/1/', N'IsFromGreekMythology', N'Data.Predicate_IsFromGreekMythology()', 0, NULL, 0, 0)
58 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/48/', N'IsMusician', N'Data.Predicate_IsMusician()', 0, NULL, 0, 0)
59 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/48/1/', N'IsOrganist', N'Data.Predicate_IsOrganist()', 0, NULL, 0, 0)
60 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/50/10/', N'IsSwimmer', N'Data.Predicate_IsSwimmer()', 0, NULL, 0, 0)
61 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/52/', N'IsLivingPerson', N'Data.Predicate_IsLivingPerson()', 0, NULL, 0, 0)
62 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/55/', N'IsSportManager', N'Data.Predicate_IsSportManager()', 0, NULL, 0, 0)
63 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/56/', N'IsCoach', N'Data.Predicate_IsCoach()', 0, NULL, 0, 0)
64 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/57/', N'IsJudge', N'Data.Predicate_IsJudge()', 0, NULL, 0, 0)
65 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/58/', N'IsModel', N'Data.Predicate_IsModel()', 0, NULL, 0, 0)
66 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/59/', N'IsKnownInIndia', N'Data.Predicate_IsKnownInIndia()', 0, NULL, 0, 0)
67 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/60/', N'IsRugbyPlayer', N'Data.Predicate_IsRugbyPlayer()', 0, NULL, 0, 0)
68 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/61/', N'IsAmericanFootballPlayer', N'Data.Predicate_IsAmericanFootballPlayer()', 0, NULL, 0, 0)
69 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/62/', N'IsBaseballPlayer', N'Data.Predicate_IsBaseballPlayer()', 0, NULL, 0, 0)
70 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/63/', N'IsBasketballPlayer', N'Data.Predicate_IsBasketballPlayer()', 0, NULL, 0, 0)
71 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/64/', N'IsBoxer', N'Data.Predicate_IsBoxer()', 0, NULL, 0, 0)
72 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/65/', N'IsFigureSkater', N'Data.Predicate_IsFigureSkater()', 0, NULL, 0, 0)
73 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/66/', N'IsFootballPlayer', N'Data.Predicate_IsFootballPlayer()', 0, NULL, 0, 0)
74 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/67/', N'IsGymnast', N'Data.Predicate_IsGymnast()', 0, NULL, 0, 0)
75 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/68/', N'IsIceHockeyPlayer', N'Data.Predicate_IsIceHockeyPlayer()', 0, NULL, 0, 0)
76 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/69/', N'IsMotorsportRacer', N'Data.Predicate_IsMotorsportRacer()', 0, NULL, 0, 0)
77 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/70/', N'IsRacingDriver', N'Data.Predicate_IsRacingDriver()', 0, NULL, 0, 0)
78 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/71/', N'IsTelevisionTalkShowHosts', N'Data.Predicate_IsTelevisionTalkShowHosts()', 0, NULL, 0, 0)
79 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/72/', N'Location', N'Data.Predicate_Location()', 0, NULL, 1, 0)
80 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/73/', N'DealsWithRaceHorses', N'Data.Predicate_DealsWithRaceHorses()', 0, NULL, 0, 0)
81 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/74/', N'IsComposer', N'Data.Predicate_IsComposer()', 0, NULL, 0, 0)
82 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/74/1/', N'IsBaroqueComposer', N'Data.Predicate_IsBaroqueComposer()', 0, NULL, 0, 0)
83 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/75/', N'IsPracticingMartialArts', N'Data.Predicate_IsPracticingMartialArts()', 0, NULL, 0, 0)
84 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/76/', N'Sex', N'Data.Predicate_Sex()', 0, NULL, 1, 0)
85 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/76/1/', N'IsMale', N'Data.Predicate_IsMale()', 0, N'/76/', 1, 0)
86 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/76/2/', N'IsFemale', N'Data.Predicate_IsFemale()', 0, N'/76/', 0, 0)
87 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/84/', N'WasBornInIndia', N'Data.Predicate_WasBornInIndia()', 0, NULL, 0, 0)
88 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/86/', N'WasBornInAustraliaOrNewZeland', N'Data.Predicate_WasBornInAustraliaOrNewZeland()', 0, NULL, 0, 0)
89 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/98/', N'WasBornInNorthAmerica', N'Data.Predicate_WasBornInNorthAmerica()', 1, NULL, 0, 0)
90 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/98/1/', N'WasBornInUSA', N'Data.Predicate_WasBornInUSA()', 0, NULL, 0, 0)
91 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/98/2/', N'WasBornInCanada', N'Data.Predicate_WasBornInCanada()', 0, NULL, 0, 0)
92 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/99/', N'WasBornInSouthAmerica', N'Data.Predicate_WasBornInSouthAmerica()', 1, NULL, 0, 0)
93 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/99/1/', N'WasBornInBrazil', N'Data.Predicate_WasBornInBrazil()', 0, NULL, 0, 0)
94 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/99/2/', N'WasBornInArgentina', N'Data.Predicate_WasBornInArgentina()', 0, NULL, 0, 0)
95 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/100/', N'WasBornInAfrica', N'Data.Predicate_WasBornInAfrica()', 1, NULL, 0, 0)
96 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/', N'WasBornInWesternMiddleOrNorthEurope', N'Data.Predicate_WasBornInWesternMiddleOrNorthEurope()', 1, NULL, 0, 0)
97 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/1/', N'WasBornInUnitedKingdomOrIreland', N'Data.Predicate_WasBornInUnitedKingdomOrIreland()', 0, NULL, 0, 0)
98 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/2/', N'WasBornInGermany', N'Data.Predicate_WasBornInGermany()', 0, NULL, 0, 0)
99 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/3/', N'WasBornInFrance', N'Data.Predicate_WasBornInFrance()', 0, NULL, 0, 0)
100 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/4/', N'WasBornInItaly', N'Data.Predicate_WasBornInItaly()', 0, NULL, 0, 0)
101 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/5/', N'WasBornInSpain', N'Data.Predicate_WasBornInSpain()', 0, NULL, 0, 0)
102 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/6/', N'WasBornInSweden', N'Data.Predicate_WasBornInSweden()', 0, NULL, 0, 0)
103 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/7/', N'WasBornInNetherlands', N'Data.Predicate_WasBornInNetherlands()', 0, NULL, 0, 0)
104 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/101/8/', N'WasBornInPoland', N'Data.Predicate_WasBornInPoland()', 0, NULL, 0, 0)
105 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/102/', N'WasBornInMidleEast', N'Data.Predicate_WasBornInMidleEast()', 1, NULL, 0, 0)
106 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/102/1/', N'WasBornInIsrael', N'Data.Predicate_WasBornInIsrael()', 0, NULL, 0, 0)
107 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/102/2/', N'WasBornInTurkey', N'Data.Predicate_WasBornInTurkey()', 0, NULL, 0, 0)
108 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/103/', N'WasBornInFarEast', N'Data.Predicate_WasBornInFarEast()', 1, NULL, 0, 0)
109 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/103/1/', N'WasBornInJapan', N'Data.Predicate_WasBornInJapan()', 0, NULL, 0, 0)
110 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/103/2/', N'WasBornInKorea', N'Data.Predicate_WasBornInKorea()', 0, NULL, 0, 0)
111 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/103/3/', N'WasBornInChina', N'Data.Predicate_WasBornInChina()', 0, NULL, 0, 0)
112 | INSERT [Data].[PredicateType] ([PredicateID], [Name], [Expression], [Computed], [ScopePredicateID], [Hidden], [Imprecise]) VALUES (N'/104/', N'WasBornInRussiaOrInSovietUnion', N'Data.Predicate_WasBornInRussiaOrInSovietUnion()', 0, NULL, 0, 0)
113 |
--------------------------------------------------------------------------------
/SQL/README.md:
--------------------------------------------------------------------------------
1 | To setup the solution you should:
2 |
3 | - create a database;
4 | - run scripts.sql to create tables, views, and other SQL related objects
5 | - run page_compression.sql, to change compression scheme for the tables (optional step, which requires advanced SQL Server editions);
6 | - Continue to Persons, if you want to populate data with DBpedia Persons data set.
7 |
8 |
9 | Play the game.
10 | The initial call is like this:
11 | declare @params xml;
12 | declare @result xml;
13 |
14 | execute Data.GetNextPredicates @params = @params, @result = @result output;
15 |
16 | select @result;
17 |
18 | This returns the first offers like this:
19 | <question name="IsLivingPerson" />
20 |
21 | Then the second request can be like this
22 | declare @params xml = '
23 | <request>
24 | <question name="IsLivingPerson" answer="1"/>
25 | </request>';
26 |
27 | declare @result xml;
28 |
29 | execute Data.GetNextPredicates @params = @params, @result = @result output;
30 |
31 | select @result;
32 |
33 | This returns the second offers like this:
34 | <question name="IsFootballPlayer" />
35 |
36 | So, you will continue to add questions to request and fill answers until there is nothing to offer.
37 | Once you descended to the last predicate, you can get entities matched:
38 | declare @params xml = '
39 | <request>
40 | <question name="IsLivingPerson" answer="1"/>
41 | <question name="IsFootballPlayer" answer="1"/>
42 | </request>';
43 |
44 | declare @result xml;
45 |
46 | execute Data.GetEntities @params = @params;
47 |
--------------------------------------------------------------------------------
/SQL/page_compression.sql:
--------------------------------------------------------------------------------
1 | -- Run this script after script.sql.
2 | -- This script changes type compression of tables to PAGE;
3 | -- this greatly reduces the size of the database, and even boosts the performance.
4 | -- Unfortunately not every SQL Server edition supports this.
5 |
6 | ALTER TABLE [Data].[PropertyType] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
7 | GO
8 |
9 | ALTER TABLE [Data].[PredicateType] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
10 | GO
11 |
12 | ALTER TABLE [Data].[Entity] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
13 | GO
14 |
15 | ALTER TABLE [Data].[Property] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
16 | GO
17 |
18 | ALTER TABLE [Data].[Predicate] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
19 | GO
20 |
21 | ALTER TABLE [Data].[PredicateTree] REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE)
22 | GO
23 |
--------------------------------------------------------------------------------
/SQL/scripts.sql:
--------------------------------------------------------------------------------
1 | -- Simplest form of create database statement.
2 | -- CREATE DATABASE KB;
3 | -- USE KB;
4 |
5 | CREATE SCHEMA [Data]
6 | GO
7 | CREATE SCHEMA [Dynamic]
8 | GO
9 | CREATE SCHEMA [Metadata]
10 | GO
11 | CREATE XML SCHEMA COLLECTION [Data].[XmlTypes] AS N''
12 | GO
13 |
14 | CREATE SEQUENCE [Data].[EntityID] AS [int] START WITH 1
15 | GO
16 |
17 | CREATE SEQUENCE [Data].[PropertyID] AS [int] START WITH 1
18 | GO
19 |
20 | CREATE SEQUENCE [Data].[PredicateTreeID] AS [int] START WITH 1
21 | GO
22 |
23 | SET ANSI_NULLS ON
24 | GO
25 | SET QUOTED_IDENTIFIER ON
26 | GO
27 |
28 | CREATE FUNCTION [Data].[GetPredicateID]
29 | (
30 | @name nvarchar(128)
31 | )
32 | returns hierarchyid
33 | as
34 | begin
35 | return
36 | (
37 | select
38 | PredicateID
39 | from
40 | Data.PredicateType
41 | where
42 | Name = @name
43 | );
44 | end
45 |
46 | GO
47 | SET ANSI_NULLS ON
48 | GO
49 | SET QUOTED_IDENTIFIER ON
50 | GO
51 | CREATE FUNCTION [Data].[GetPropertyID]
52 | (
53 | @name nvarchar(128)
54 | )
55 | returns int
56 | as
57 | begin
58 | return
59 | (
60 | select
61 | PropertyID
62 | from
63 | Data.PropertyType
64 | where
65 | Name = @name
66 | );
67 | end
68 | GO
69 | SET ANSI_NULLS ON
70 | GO
71 | SET QUOTED_IDENTIFIER ON
72 | GO
73 | CREATE function [Dynamic].[GetSQL_GetEntities]
74 | (
75 | -- Request parameters.
76 | @params xml,
77 | -- Number of rows to return
78 | @take int,
79 | -- Optional property value to return.
80 | @property nvarchar(128)
81 | )
82 | returns nvarchar(max)
83 | as
84 | begin
85 | declare @sql nvarchar(max);
86 |
87 | with Data as
88 | (
89 | select cast(isnull(@params, '') as xml(document Data.XmlTypes)) Data
90 | ),
91 | Predicate as
92 | (
93 | select
94 | row_number() over(order by Node) Row,
95 | P.PredicateID,
96 | P.Name,
97 | P.ScopePredicateID,
98 | (
99 | select
100 | S.Expression
101 | from
102 | Data.PredicateType S with(forceseek)
103 | where
104 | (S.PredicateID = P.ScopePredicateID) and
105 | (S.Computed = 1)
106 | ) ScopeExpression,
107 | iif(P.Computed = 1, P.Expression, null) Expression,
108 | case when P.Imprecise = 1
109 | then cast(Q.Answer * 0.8 + 0.1 as decimal(2, 1))
110 | else Q.Answer
111 | end Answer
112 | from
113 | Data
114 | cross apply
115 | Data.nodes('/request/*') N(Node)
116 | inner loop join
117 | Data.PredicateType P
118 | on
119 | P.Name = Node.value('self::question/@name', 'nvarchar(128)')
120 | cross apply
121 | (select Node.value('self::question/@answer', 'decimal(2, 1)') Answer) Q
122 | ),
123 | Params as
124 | (
125 | select
126 | @take Take,
127 | (
128 | select top 1
129 | PropertyID
130 | from
131 | Data.PropertyType
132 | where
133 | Name = @property
134 | ) PropertyID,
135 | (
136 | select
137 | *
138 | from
139 | Predicate
140 | order by
141 | Row
142 | for xml auto, type
143 | ) Predicates
144 | )
145 | select
146 | @sql = Dynamic.ToSQL(isnull(Predicates, '').query(N'
147 | let $take := xs:integer(sql:column("Take"))
148 | let $propertyID := xs:integer(sql:column("PropertyID"))
149 | let $predicates := Predicate
150 | let $positivePredicates := $predicates[xs:decimal(@Answer) = 1]
151 | let $negativePredicates := $predicates[xs:decimal(@Answer) = 0]
152 | let $otherPredicates := $predicates[not(xs:decimal(@Answer) = (0, 0.5, 1))]
153 | return
154 | (
155 | with ,
156 |
157 | for $predicate in $predicates
158 | let $row := xs:integer($predicate/@Row)
159 | let $predicateID := xs:string($predicate/@PredicateID)
160 | let $name := xs:string($predicate/@Name)
161 | let $expression := xs:string($predicate/@Expression)
162 | let $answer := xs:decimal($predicate/@Answer)
163 | let $scopePredicateID := xs:string($predicate/@ScopePredicateID)
164 | let $scopeExpression := xs:string($predicate/@ScopeExpression)
165 | return
166 | (
167 | P{$row} as -- {$name}
168 | (
169 | ,
170 |
171 | if (empty($expression) or ($expression = "")) then
172 | (
173 | select EntityID from Data.Predicate with(forceseek) where PredicateID = {$predicateID}
174 | )
175 | else
176 | (
177 | select EntityID from {$expression}
178 | ),
179 |
180 | if (not(empty($scopePredicateID)) and ($answer = 1)) then
181 | (
182 |
183 | union all
184 | (
185 | select EntityID from Data.Entity
186 | except
187 | select EntityID from ,
188 |
189 | if (empty($scopeExpression) or ($scopeExpression = "")) then
190 | (
191 | Data.Predicate with(forceseek) where PredicateID = {$scopePredicateID}
192 | )
193 | else
194 | (
195 | {$scopeExpression}
196 | ),
197 |
198 |
199 | )
200 | )
201 | else
202 | (),
203 |
204 |
205 | ),
206 |
207 | ),
208 |
209 | M as
210 | (
211 | ,
212 |
213 | if (empty($positivePredicates)) then
214 | (
215 | select EntityID from Data.Entity
216 | )
217 | else
218 | (
219 | let $firstRow := xs:integer($positivePredicates[1]/@Row)
220 | for $predicate in $positivePredicates
221 | let $row := xs:integer($predicate/@Row)
222 | return
223 | (
224 | if ($row != $firstRow) then
225 | (
226 |
227 | intersect
228 |
229 | )
230 | else
231 | (),
232 |
233 | select EntityID from P{$row}
234 | )
235 | ),
236 |
237 | for $predicate in $negativePredicates
238 | let $row := xs:integer($predicate/@Row)
239 | return
240 | (
241 |
242 | except
243 | select EntityID from P{$row}
244 | ),
245 |
246 |
247 | ),,
248 |
249 |
250 | if (empty($otherPredicates)) then
251 | (
252 |
253 | E as
254 | (
255 | select 1 W, EntityID from M
256 | )
257 | )
258 | else
259 | (
260 |
261 | E as
262 | (
263 | select
264 | ,
265 |
266 | let $lastRow := xs:integer($otherPredicates[last()]/@Row)
267 | for $predicate in $otherPredicates
268 | let $row := xs:integer($predicate/@Row)
269 | let $answer := xs:decimal($predicate/@Answer)
270 | return
271 | (
272 | iif(EntityID in (select EntityID from P{$row}), {$answer}, {1 - $answer}),
273 |
274 | if ($row = $lastRow) then
275 | ()
276 | else
277 | (
278 | *
279 |
280 | )
281 | ),
282 |
283 | W,
284 | EntityID
285 | from
286 | M
287 | )
288 | ),
289 |
290 | ,
291 | C as
292 | (
293 | select min(W) W from E
294 | )
295 | select,
296 |
297 | if (empty($take)) then
298 | ()
299 | else
300 | (
301 | top ({$take})
302 | ),
303 |
304 |
305 | E.EntityID,
306 | {
307 | if (empty($propertyID)) then
308 | (
309 | null Value
310 | )
311 | else
312 | (
313 | P.Value
314 | )
315 | }
316 | from
317 | E
318 | inner join
319 | C
320 | on
321 | E.W = C.W
322 | ,
323 |
324 | if (empty($propertyID)) then
325 | ()
326 | else
327 | (
328 | left join
329 | Data.Property P
330 | on
331 | (P.EntityID = E.EntityID) and
332 | (P.PropertyID = {$propertyID})
333 | ),
334 |
335 |
336 | order by
337 | Value,
338 | E.EntityID
339 | )'))
340 | from
341 | Params;
342 |
343 | return @sql;
344 | end;
345 | GO
346 | SET ANSI_NULLS ON
347 | GO
348 | SET QUOTED_IDENTIFIER ON
349 | GO
350 | CREATE function [Dynamic].[GetSQL_GetNextPredicate]
351 | (
352 | -- Request parameters.
353 | @params xml
354 | )
355 | returns nvarchar(max)
356 | as
357 | begin
358 | declare @sql nvarchar(max);
359 |
360 | with Data as
361 | (
362 | select cast(isnull(@params, '') as xml(document Data.XmlTypes)) Data
363 | ),
364 | Predicate as
365 | (
366 | select
367 | row_number() over(order by Node) Row,
368 | P.PredicateID,
369 | P.Name,
370 | (
371 | select top 1
372 | 1
373 | from
374 | Data.PredicateType A with(forceseek)
375 | where
376 | (P.PredicateID != A.PredicateID) and
377 | (P.PredicateID.IsDescendantOf(A.PredicateID) = 1) and
378 | (A.Hidden = 0)
379 | ) HasAncestors,
380 | (
381 | select top 1
382 | 1
383 | from
384 | Data.PredicateType D with(forceseek)
385 | where
386 | (P.PredicateID != D.PredicateID) and
387 | (D.PredicateID.IsDescendantOf(P.PredicateID) = 1) and
388 | (D.Hidden = 0)
389 | ) HasDescendants,
390 | P.ScopePredicateID,
391 | (
392 | select
393 | S.Expression
394 | from
395 | Data.PredicateType S with(forceseek)
396 | where
397 | (S.PredicateID = P.ScopePredicateID) and
398 | (S.Computed = 1)
399 | ) ScopeExpression,
400 | iif(P.Computed = 1, P.Expression, null) Expression,
401 | case when P.Imprecise = 1
402 | then cast(Q.Answer * 0.8 + 0.1 as decimal(2, 1))
403 | else Q.Answer
404 | end Answer
405 | from
406 | Data
407 | cross apply
408 | Data.nodes('/request/*') N(Node)
409 | inner loop join
410 | Data.PredicateType P
411 | on
412 | P.Name = Node.value('self::question/@name', 'nvarchar(128)')
413 | cross apply
414 | (select Node.value('self::question/@answer', 'decimal(2, 1)') Answer) Q
415 | ),
416 | Params as
417 | (
418 | select
419 | (
420 | select
421 | *
422 | from
423 | Predicate
424 | order by
425 | Row
426 | for xml auto, type
427 | ) Predicates
428 | )
429 | select
430 | @sql = Dynamic.ToSQL(isnull(Predicates, '').query(N'
431 | let $predicates := Predicate
432 | let $positivePredicates := $predicates[xs:decimal(@Answer) = 1]
433 | let $negativePredicates := $predicates[xs:decimal(@Answer) = 0]
434 | let $otherPredicates := $predicates[not(xs:decimal(@Answer) = (0, 0.5, 1))]
435 | return
436 | (
437 | with ,
438 |
439 | for $predicate in $predicates
440 | let $row := xs:integer($predicate/@Row)
441 | let $predicateID := xs:string($predicate/@PredicateID)
442 | let $name := xs:string($predicate/@Name)
443 | let $expression := xs:string($predicate/@Expression)
444 | let $answer := xs:decimal($predicate/@Answer)
445 | let $scopePredicateID := xs:string($predicate/@ScopePredicateID)
446 | let $scopeExpression := xs:string($predicate/@ScopeExpression)
447 | return
448 | (
449 | P{$row} as -- {$name}
450 | (
451 | ,
452 |
453 | if (empty($expression) or ($expression = "")) then
454 | (
455 | select EntityID from Data.Predicate with(forceseek) where PredicateID = {$predicateID}
456 | )
457 | else
458 | (
459 | select EntityID from {$expression}
460 | ),
461 |
462 | if (not(empty($scopePredicateID)) and ($answer = 1)) then
463 | (
464 |
465 | union all
466 | (
467 | select EntityID from Data.Entity
468 | except
469 | select EntityID from ,
470 |
471 | if (empty($scopeExpression) or ($scopeExpression = "")) then
472 | (
473 | Data.Predicate with(forceseek) where PredicateID = {$scopePredicateID}
474 | )
475 | else
476 | (
477 | {$scopeExpression}
478 | ),
479 |
480 |
481 | )
482 | )
483 | else
484 | (),
485 |
486 |
487 | ),
488 |
489 | ),
490 |
491 | M as
492 | (
493 | ,
494 |
495 | if ($positivePredicates) then
496 | (
497 | let $firstRow := xs:integer($positivePredicates[1]/@Row)
498 | for $predicate in $positivePredicates
499 | let $row := xs:integer($predicate/@Row)
500 | return
501 | (
502 | if ($row != $firstRow) then
503 | (
504 |
505 | intersect
506 |
507 | )
508 | else
509 | (),
510 |
511 | select EntityID from P{$row}
512 | )
513 | )
514 | else if ($otherPredicates or empty($negativePredicates)) then
515 | (
516 | select EntityID from Data.Entity
517 | )
518 | else
519 | (),
520 |
521 | if ($positivePredicates or $otherPredicates or empty($negativePredicates)) then
522 | (
523 | for $predicate in $negativePredicates
524 | let $row := xs:integer($predicate/@Row)
525 | return
526 | (
527 |
528 | except
529 | select EntityID from P{$row}
530 | )
531 | )
532 | else
533 | (
534 | let $firstRow := xs:integer($negativePredicates[1]/@Row)
535 | for $predicate in $negativePredicates
536 | let $row := xs:integer($predicate/@Row)
537 | return
538 | (
539 | if ($row != $firstRow) then
540 | (
541 |
542 | union
543 |
544 | )
545 | else
546 | (),
547 |
548 | select EntityID from P{$row}
549 | )
550 | ),
551 |
552 |
553 | ),,
554 |
555 |
556 | if (empty($otherPredicates)) then
557 | (
558 |
559 | P as
560 | (
561 | select
562 | 1 W,
563 | P.PredicateID,
564 | count(*) C,
565 | ,
566 |
567 | if ($positivePredicates or empty($negativePredicates)) then
568 | (
569 | (select count(*) from M)
570 | )
571 | else
572 | (
573 | (:(select count(*) from Data.Entity) - (select count(*) from M):)
574 | (select EntityCount from Data.Entities with(noexpand)) - (select count(*) from M)
575 | ),
576 |
577 | TC
578 | from
579 |
580 | )
581 | else
582 | (
583 |
584 | E as
585 | (
586 | select
587 | ,
588 |
589 | let $lastRow := xs:integer($otherPredicates[last()]/@Row)
590 | for $predicate in $otherPredicates
591 | let $row := xs:integer($predicate/@Row)
592 | let $answer := xs:decimal($predicate/@Answer)
593 | return
594 | (
595 | iif(EntityID in (select EntityID from P{$row}), {$answer}, {1 - $answer}),
596 |
597 | if ($row = $lastRow) then
598 | ()
599 | else
600 | (
601 | *
602 |
603 | )
604 | ),
605 |
606 | W,
607 | EntityID
608 | from
609 | M
610 | ),
611 | P as
612 | (
613 | select distinct
614 | E.W,
615 | P.PredicateID,
616 | count(*) over(partition by E.W, P.PredicateID) C,
617 | count(*) over(partition by E.W) TC
618 | from
619 |
620 | ),
621 |
622 | Data.Predicate P,
623 |
624 | if ($positivePredicates) then
625 | (
626 | with(forceseek, index(IX_Predicate_Entity))
627 | )
628 | else if ($negativePredicates or $otherPredicates) then
629 | (
630 | with(forceseek)
631 | )
632 | else
633 | (),
634 |
635 | if ($otherPredicates) then
636 | (
637 |
638 | inner join
639 | E
640 | on
641 | P.EntityID = E.EntityID
642 | )
643 | else
644 | (),
645 |
646 |
647 | where
648 | (P.PredicateID in (select PredicateID from Data.PredicateType where Hidden = 0)),
649 |
650 | if ($otherPredicates) then
651 | ()
652 | else if ($positivePredicates) then
653 | (
654 | and
655 | (P.EntityID in (select EntityID from M))
656 | )
657 | else
658 | (
659 | for $predicate in $negativePredicates
660 | let $row := xs:integer($predicate/@Row)
661 | return
662 | (
663 | and
664 | (P.EntityID not in (select EntityID from P{$row}))
665 | )
666 | ),
667 |
668 | for $predicate in $predicates
669 | let $predicateID := xs:string($predicate/@PredicateID)
670 | let $hasDescendants := xs:boolean($predicate/@HasDescendants)
671 | let $hasAncestors := xs:boolean($predicate/@HasAncestors)
672 | let $answer := xs:decimal($predicate/@Answer)
673 | return
674 | (
675 | if (($answer = 1) and $hasAncestors) then
676 | (
677 | and
678 | (cast({$predicateID} as hierarchyid).IsDescendantOf(P.PredicateID) = 0)
679 | )
680 | else if (($answer = 0) and $hasDescendants) then
681 | (
682 | and
683 | (P.PredicateID.IsDescendantOf({$predicateID}) = 0)
684 | )
685 | else
686 | (
687 | and
688 | (P.PredicateID != {$predicateID})
689 | )
690 | ),
691 |
692 | if ($otherPredicates) then
693 | ()
694 | else
695 | (
696 |
697 | group by
698 | P.PredicateID
699 | ),
700 |
701 |
702 | ),
703 | R as
704 | (
705 | select
706 | W Weight,
707 | cast(abs(1 - 2.0 * C / TC) as decimal(2, 1)) Deviation,
708 | PredicateID
709 | from
710 | P
711 | )
712 | )'))
713 | from
714 | Params;
715 |
716 | return @sql;
717 | end;
718 | GO
719 | SET ANSI_NULLS ON
720 | GO
721 | SET QUOTED_IDENTIFIER ON
722 | GO
723 | -- Builds a text of SQL function for an sql template.
724 | CREATE function [Dynamic].[ToSQL]
725 | (
726 | -- SQL template.
727 | -- Following is the xml schema of the template:
728 | /*
729 | ;
731 |
732 |
733 |
734 | A base element.
735 |
736 |
737 |
738 |
739 |
740 | An SQL content.
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 | A quoted name.
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 | A string literal.
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 | A fulltext string literal.
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 | An int value.
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 | A decimal value.
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 | A date value.
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 | A time value.
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 | A dateTime value.
810 |
811 |
812 |
813 |
814 |
815 | */
816 | @template xml
817 | )
818 | returns nvarchar(max)
819 | with returns null on null input
820 | as
821 | begin
822 | return isnull
823 | (
824 | (
825 | select
826 | case
827 | when Name = '' then Value
828 | when Name = 'name' then quotename(Value, '[')
829 | when Nil = 1 then 'null'
830 | when
831 | (Name = 'int') and
832 | (try_convert(int, Value) is not null)
833 | then
834 | Value
835 | when Name = 'string' then
836 | 'N''' + replace(Value, '''', '''''') + ''''
837 | when
838 | (Name = 'datetime') and
839 | (try_convert(datetime2, Value, 126) is not null)
840 | then
841 | 'convert(datetime2, N''' + Value + ''', 126)'
842 | when
843 | (Name = 'date') and
844 | (try_convert(date, Value, 126) is not null)
845 | then
846 | 'convert(date, N''' + Value + ''', 126)'
847 | when
848 | (Name = 'decimal') and
849 | (try_convert(money, Value) is not null)
850 | then
851 | Value
852 | when
853 | (Name = 'time') and
854 | (try_convert(time, Value, 114) is not null)
855 | then
856 | 'convert(time, N''' + Value + ''', 114)'
857 | --when Name = 'fulltext' then
858 | -- 'N''' +
859 | -- --replace(System.PrepareSearchText(Value), '''', '''''') +
860 | -- ''''
861 | else '# ' + Name + ' #'
862 | end
863 | from
864 | @template.nodes('//sql/node()[not(self::sql)]') N(Node)
865 | cross apply
866 | (
867 | select
868 | Node.value('local-name(.)', 'nvarchar(128)') Name,
869 | Node.value('@xsi:nil', 'bit') Nil,
870 | Node.value('.', 'nvarchar(max)') Value
871 | ) V
872 | for xml path(''), type
873 | ).value('.', 'nvarchar(max)'),
874 |
875 | ''
876 | );
877 | end;
878 |
879 | GO
880 | SET ANSI_NULLS ON
881 | GO
882 | SET QUOTED_IDENTIFIER ON
883 | GO
884 | CREATE TABLE [Data].[Entity](
885 | [EntityID] [int] NOT NULL,
886 | CONSTRAINT [PK_Entity] PRIMARY KEY CLUSTERED
887 | (
888 | [EntityID] ASC
889 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
890 | ) ON [PRIMARY]
891 |
892 | GO
893 | SET ANSI_NULLS ON
894 | GO
895 | SET QUOTED_IDENTIFIER ON
896 | GO
897 | CREATE TABLE [Data].[Predicate](
898 | [PredicateID] [hierarchyid] NOT NULL,
899 | [EntityID] [int] NOT NULL,
900 | CONSTRAINT [PK_Predicate] PRIMARY KEY CLUSTERED
901 | (
902 | [PredicateID] ASC,
903 | [EntityID] ASC
904 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
905 | ) ON [PRIMARY]
906 |
907 | GO
908 | SET ANSI_NULLS ON
909 | GO
910 | SET QUOTED_IDENTIFIER ON
911 | GO
912 | CREATE TABLE [Data].[PredicateTree](
913 | [ID] [int] NOT NULL,
914 | [ParentID] [int] NOT NULL,
915 | [Answer] [decimal](2, 1) NOT NULL,
916 | [PredicateID] [hierarchyid] NULL,
917 | [Populated] [bit] NOT NULL,
918 | CONSTRAINT [PK_PredicateTree] PRIMARY KEY CLUSTERED
919 | (
920 | [ID] ASC
921 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
922 | ) ON [PRIMARY]
923 |
924 | GO
925 | SET ANSI_NULLS ON
926 | GO
927 | SET QUOTED_IDENTIFIER ON
928 | GO
929 | CREATE TABLE [Data].[PredicateType](
930 | [PredicateID] [hierarchyid] NOT NULL,
931 | [Name] [nvarchar](128) NOT NULL,
932 | [Expression] [nvarchar](max) NULL,
933 | [Computed] [bit] NOT NULL CONSTRAINT [DF_PredicateType_Computed] DEFAULT ((0)),
934 | [ScopePredicateID] [hierarchyid] NULL,
935 | [Hidden] [bit] NOT NULL CONSTRAINT [DF_PredicateType_Scope] DEFAULT ((0)),
936 | [Imprecise] [bit] NOT NULL CONSTRAINT [DF_PredicateType_Imprecise] DEFAULT ((0)),
937 | CONSTRAINT [PK_PredicateType] PRIMARY KEY CLUSTERED
938 | (
939 | [PredicateID] ASC
940 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
941 | ) ON [PRIMARY]
942 |
943 | GO
944 | SET ANSI_NULLS ON
945 | GO
946 | SET QUOTED_IDENTIFIER ON
947 | GO
948 | CREATE TABLE [Data].[Property](
949 | [EntityID] [int] NOT NULL,
950 | [PropertyID] [int] NOT NULL,
951 | [Value] [nvarchar](4000) NULL
952 | ) ON [PRIMARY]
953 |
954 | GO
955 | CREATE CLUSTERED INDEX [IX_Property_Property] ON [Data].[Property]
956 | (
957 | [PropertyID] ASC,
958 | [EntityID] ASC
959 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
960 | GO
961 | SET ANSI_NULLS ON
962 | GO
963 | SET QUOTED_IDENTIFIER ON
964 | GO
965 | CREATE TABLE [Data].[PropertyType](
966 | [PropertyID] [int] NOT NULL,
967 | [Name] [nvarchar](128) NOT NULL,
968 | [Type] [nvarchar](256) NOT NULL,
969 | CONSTRAINT [PK_PropertyType] PRIMARY KEY CLUSTERED
970 | (
971 | [PropertyID] ASC
972 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
973 | ) ON [PRIMARY]
974 |
975 | GO
976 | SET ANSI_NULLS ON
977 | GO
978 | SET QUOTED_IDENTIFIER ON
979 | GO
980 | CREATE function [Data].[GetEntityProperties](@name nvarchar(128))
981 | returns table
982 | as
983 | return
984 | select
985 | P.*
986 | from
987 | Data.PropertyType T
988 | inner join
989 | Data.Property P
990 | on
991 | (T.Name = @name) and
992 | (T.PropertyID = P.PropertyID);
993 |
994 | GO
995 | SET ANSI_NULLS ON
996 | GO
997 | SET QUOTED_IDENTIFIER ON
998 | GO
999 | CREATE view [Data].[Entities]
1000 | with schemabinding
1001 | as
1002 | select
1003 | count_big(*) EntityCount
1004 | from
1005 | Data.Entity;
1006 |
1007 | GO
1008 | SET ARITHABORT ON
1009 | SET CONCAT_NULL_YIELDS_NULL ON
1010 | SET QUOTED_IDENTIFIER ON
1011 | SET ANSI_NULLS ON
1012 | SET ANSI_PADDING ON
1013 | SET ANSI_WARNINGS ON
1014 | SET NUMERIC_ROUNDABORT OFF
1015 |
1016 | GO
1017 | CREATE UNIQUE CLUSTERED INDEX [PK_Entities] ON [Data].[Entities]
1018 | (
1019 | [EntityCount] ASC
1020 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1021 | GO
1022 | SET ANSI_NULLS ON
1023 | GO
1024 | SET QUOTED_IDENTIFIER ON
1025 | GO
1026 | create view [Data].[PredicateEntities]
1027 | with schemabinding
1028 | as
1029 | select
1030 | PredicateID, count_big(*) EntityCount
1031 | from
1032 | Data.Predicate
1033 | group by
1034 | PredicateID
1035 | GO
1036 | SET ARITHABORT ON
1037 | SET CONCAT_NULL_YIELDS_NULL ON
1038 | SET QUOTED_IDENTIFIER ON
1039 | SET ANSI_NULLS ON
1040 | SET ANSI_PADDING ON
1041 | SET ANSI_WARNINGS ON
1042 | SET NUMERIC_ROUNDABORT OFF
1043 |
1044 | GO
1045 | CREATE UNIQUE CLUSTERED INDEX [PK_PredicateEntities] ON [Data].[PredicateEntities]
1046 | (
1047 | [PredicateID] ASC
1048 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1049 | GO
1050 | SET ANSI_NULLS ON
1051 | GO
1052 | SET QUOTED_IDENTIFIER ON
1053 | GO
1054 | CREATE view [Data].[PropertyEntities]
1055 | with schemabinding
1056 | as
1057 | select
1058 | PropertyID, count_big(*) EntityCount
1059 | from
1060 | Data.Property
1061 | group by
1062 | PropertyID;
1063 |
1064 |
1065 |
1066 |
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 | GO
1074 | SET ARITHABORT ON
1075 | SET CONCAT_NULL_YIELDS_NULL ON
1076 | SET QUOTED_IDENTIFIER ON
1077 | SET ANSI_NULLS ON
1078 | SET ANSI_PADDING ON
1079 | SET ANSI_WARNINGS ON
1080 | SET NUMERIC_ROUNDABORT OFF
1081 |
1082 | GO
1083 | CREATE UNIQUE CLUSTERED INDEX [PK_PropertyEntities] ON [Data].[PropertyEntities]
1084 | (
1085 | [PropertyID] ASC
1086 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1087 | GO
1088 | CREATE UNIQUE NONCLUSTERED INDEX [IX_Predicate_Entity] ON [Data].[Predicate]
1089 | (
1090 | [EntityID] ASC,
1091 | [PredicateID] ASC
1092 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1093 | GO
1094 | CREATE UNIQUE NONCLUSTERED INDEX [IX_PredicateTree] ON [Data].[PredicateTree]
1095 | (
1096 | [ParentID] ASC,
1097 | [Answer] ASC,
1098 | [PredicateID] ASC
1099 | )
1100 | INCLUDE ( [Populated]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1101 | GO
1102 | SET ANSI_PADDING ON
1103 |
1104 | GO
1105 | CREATE UNIQUE NONCLUSTERED INDEX [IX_PredicateType] ON [Data].[PredicateType]
1106 | (
1107 | [Name] ASC
1108 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1109 | GO
1110 | CREATE NONCLUSTERED INDEX [IX_Property_Entity] ON [Data].[Property]
1111 | (
1112 | [EntityID] ASC,
1113 | [PropertyID] ASC
1114 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1115 | GO
1116 | SET ANSI_PADDING ON
1117 |
1118 | GO
1119 | CREATE NONCLUSTERED INDEX [IX_PropertyType] ON [Data].[PropertyType]
1120 | (
1121 | [Name] ASC
1122 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1123 | GO
1124 | SET ARITHABORT ON
1125 | SET CONCAT_NULL_YIELDS_NULL ON
1126 | SET QUOTED_IDENTIFIER ON
1127 | SET ANSI_NULLS ON
1128 | SET ANSI_PADDING ON
1129 | SET ANSI_WARNINGS ON
1130 | SET NUMERIC_ROUNDABORT OFF
1131 |
1132 | GO
1133 | CREATE NONCLUSTERED INDEX [IX_PredicateEntities_EntityCount] ON [Data].[PredicateEntities]
1134 | (
1135 | [EntityCount] ASC
1136 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1137 | GO
1138 | SET ARITHABORT ON
1139 | SET CONCAT_NULL_YIELDS_NULL ON
1140 | SET QUOTED_IDENTIFIER ON
1141 | SET ANSI_NULLS ON
1142 | SET ANSI_PADDING ON
1143 | SET ANSI_WARNINGS ON
1144 | SET NUMERIC_ROUNDABORT OFF
1145 |
1146 | GO
1147 | CREATE NONCLUSTERED INDEX [IX_PropertyEntities_EntityCount] ON [Data].[PropertyEntities]
1148 | (
1149 | [EntityCount] ASC
1150 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
1151 | GO
1152 | ALTER TABLE [Data].[PredicateTree] ADD CONSTRAINT [DF_PredicateTree_ID] DEFAULT (NEXT VALUE FOR [Data].[PredicateTreeID]) FOR [ID]
1153 | GO
1154 | ALTER TABLE [Data].[PredicateTree] ADD CONSTRAINT [DF_PredicateTree_Populated] DEFAULT ((0)) FOR [Populated]
1155 | GO
1156 | ALTER TABLE [Data].[Predicate] WITH CHECK ADD CONSTRAINT [FK_Predicate_Entity] FOREIGN KEY([EntityID])
1157 | REFERENCES [Data].[Entity] ([EntityID])
1158 | ON UPDATE CASCADE
1159 | ON DELETE CASCADE
1160 | GO
1161 | ALTER TABLE [Data].[Predicate] CHECK CONSTRAINT [FK_Predicate_Entity]
1162 | GO
1163 | ALTER TABLE [Data].[Property] WITH NOCHECK ADD CONSTRAINT [FK_Property_Entity] FOREIGN KEY([EntityID])
1164 | REFERENCES [Data].[Entity] ([EntityID])
1165 | ON UPDATE CASCADE
1166 | ON DELETE CASCADE
1167 | GO
1168 | ALTER TABLE [Data].[Property] CHECK CONSTRAINT [FK_Property_Entity]
1169 | GO
1170 | SET ANSI_NULLS ON
1171 | GO
1172 | SET QUOTED_IDENTIFIER ON
1173 | GO
1174 | -- Defines and populates a predicate
1175 | CREATE procedure [Data].[DefinePredicate]
1176 | (
1177 | -- A predicate name to define.
1178 | @name nvarchar(128),
1179 |
1180 | -- A predicate expression.
1181 | @expression nvarchar(max) = null,
1182 |
1183 | -- Computed indicator
1184 | @computed bit = 0,
1185 |
1186 | -- Optional parent predicate.
1187 | @parent nvarchar(128) = null,
1188 |
1189 | -- Optional scope predicate.
1190 | @scope nvarchar(128) = null,
1191 |
1192 | -- Optional value that indicates that the predicate is hidden.
1193 | @hidden bit = 0,
1194 |
1195 | -- Indicates whether the predicate lacks accuracy. Default is 0.
1196 | @imprecise bit = 0,
1197 |
1198 | -- 1 (default) to populate the predicate immediately.
1199 | @populate bit = 1,
1200 |
1201 | -- Debug indicator.
1202 | @debug bit = 0
1203 | )
1204 | as
1205 | begin
1206 | if (@debug = 0)
1207 | begin
1208 | set nocount on;
1209 | end;
1210 |
1211 | declare @parentID hierarchyid;
1212 | declare @scopeID hierarchyid;
1213 |
1214 | if (@parent is not null)
1215 | begin
1216 | set @parentID = (select PredicateID from Data.PredicateType where Name = @parent);
1217 |
1218 | if (@parentID is null)
1219 | begin
1220 | throw 51000, 'Invalid parent predicate.', 1;
1221 | end;
1222 | end
1223 | else
1224 | begin
1225 | set @parentID = '/';
1226 | end;
1227 |
1228 | if (@scope is not null)
1229 | begin
1230 | set @scopeID = (select PredicateID from Data.PredicateType where Name = @scope);
1231 |
1232 | if (@scopeID is null)
1233 | begin
1234 | throw 51000, 'Invalid scope predicate.', 1;
1235 | end;
1236 | end;
1237 |
1238 | declare @childID hierarchyid =
1239 | (
1240 | select
1241 | max(PredicateID.GetAncestor(PredicateID.GetLevel() - @parentID.GetLevel() - 1))
1242 | from
1243 | Data.PredicateType
1244 | where
1245 | (PredicateID.IsDescendantOf(@parentID) = 1) and
1246 | (PredicateID != @parentID)
1247 | );
1248 |
1249 | declare @predicateID hierarchyid = @parentID.GetDescendant(@childID, null);
1250 |
1251 | insert into Data.PredicateType(PredicateID, Name, Expression, Computed, Hidden, Imprecise, ScopePredicateID)
1252 | values(@predicateID, @name, @expression, @computed, isnull(@hidden, 0), isnull(@imprecise, 0), @scopeID);
1253 |
1254 | if ((@populate = 1) and (@computed = 0))
1255 | begin
1256 | execute Data.InvalidatePredicate @predicateID = @predicateID, @debug = @debug;
1257 | end;
1258 | end;
1259 |
1260 | GO
1261 | SET ANSI_NULLS ON
1262 | GO
1263 | SET QUOTED_IDENTIFIER ON
1264 | GO
1265 | -- Deletes a predicate. Either @name or @predicateID is required.
1266 | create procedure [Data].[DeletePredicate]
1267 | (
1268 | -- A predicate name to define.
1269 | @name nvarchar(128) = null,
1270 |
1271 | -- A predicate id.
1272 | @predicateID hierarchyid = null
1273 | )
1274 | as
1275 | begin
1276 | set nocount on;
1277 |
1278 | if (@predicateID is null)
1279 | begin
1280 | set @predicateID =
1281 | (select PredicateID from Data.PredicateType where Name = @name);
1282 | end;
1283 |
1284 | delete from Data.Predicate where PredicateID = @predicateID;
1285 | delete from Data.PredicateType where PredicateID = @predicateID;
1286 | end;
1287 |
1288 | GO
1289 | SET ANSI_NULLS ON
1290 | GO
1291 | SET QUOTED_IDENTIFIER ON
1292 | GO
1293 | -- Gets entities for predicates
1294 | CREATE procedure [Data].[GetEntities]
1295 | (
1296 | -- Request parameters.
1297 | @params xml,
1298 | -- Number of rows to return
1299 | @take int = null,
1300 | -- Optional property value to return.
1301 | @property nvarchar(128) = null,
1302 | -- Debug options
1303 | @debug bit = null
1304 | )
1305 | as
1306 | begin
1307 | set nocount on;
1308 |
1309 | -- This is to allow EF to guess type of result.
1310 | if (1 = 0)
1311 | begin
1312 | select
1313 | EntityID,
1314 | cast(null as nvarchar(4000)) Value
1315 | from
1316 | Data.Entity
1317 | end;
1318 |
1319 | declare @sql nvarchar(max) =
1320 | Dynamic.GetSQL_GetEntities(@params, @take, @property);
1321 |
1322 | if (@debug = 1)
1323 | begin
1324 | print @sql;
1325 | end;
1326 |
1327 | execute sp_executesql @sql,
1328 | @params = N'@take int, @property nvarchar(128)',
1329 | @take = @take,
1330 | @property = @property;
1331 | end;
1332 |
1333 | GO
1334 | SET ANSI_NULLS ON
1335 | GO
1336 | SET QUOTED_IDENTIFIER ON
1337 | GO
1338 | -- Gets next predicates
1339 | CREATE procedure [Data].[GetNextPredicates]
1340 | (
1341 | -- Request parameters.
1342 | @params xml,
1343 |
1344 | -- Result as a predicate
1345 | @result xml output,
1346 |
1347 | -- Debug options
1348 | @debug bit = null
1349 | )
1350 | as
1351 | begin
1352 | set nocount on;
1353 |
1354 | set @result = null;
1355 |
1356 | -- Number of rows to return
1357 | declare @take int = 5;
1358 |
1359 | declare @question table
1360 | (
1361 | PredicateID hierarchyid not null primary key,
1362 | Answer decimal(2, 1) not null
1363 | );
1364 |
1365 | declare @questionID table
1366 | (
1367 | PredicateID hierarchyid not null primary key,
1368 | ID int not null,
1369 | New bit not null
1370 | );
1371 |
1372 | with Data as
1373 | (
1374 | select cast(isnull(@params, '') as xml(document Data.XmlTypes)) Data
1375 | ),
1376 | Predicate as
1377 | (
1378 | select
1379 | P.PredicateID,
1380 | case when P.Imprecise = 1
1381 | then cast(Q.Answer * 0.8 + 0.1 as decimal(2, 1))
1382 | else Q.Answer
1383 | end Answer
1384 | from
1385 | Data
1386 | cross apply
1387 | Data.nodes('/request/*') N(Node)
1388 | inner loop join
1389 | Data.PredicateType P
1390 | on
1391 | P.Name = Node.value('self::question/@name', 'nvarchar(128)')
1392 | cross apply
1393 | (select Node.value('self::question/@answer', 'decimal(2, 1)') Answer) Q
1394 | )
1395 | insert into @question(PredicateID, Answer)
1396 | select PredicateID, Answer from Predicate;
1397 |
1398 | declare @questionCount int = @@rowcount;
1399 | declare @retry int = @questionCount;
1400 |
1401 | while(@retry > 0)
1402 | begin
1403 | set @retry -= 1;
1404 |
1405 | with Q as
1406 | (
1407 | select
1408 | cast(row_number() over(order by PredicateID) as int) Row,
1409 | *
1410 | from
1411 | @question
1412 | ),
1413 | T as
1414 | (
1415 | select
1416 | 0 Row,
1417 | 0 ID,
1418 | 0 ParentID,
1419 | cast(1 as decimal(2, 1)) Answer,
1420 | cast('/' as hierarchyid) PredicateID
1421 | union all
1422 | select
1423 | Q.Row,
1424 | P.ID,
1425 | T.ID,
1426 | Q.Answer,
1427 | Q.PredicateID
1428 | from
1429 | Q
1430 | inner join
1431 | T
1432 | on
1433 | Q.Row = T.Row + 1
1434 | inner join
1435 | Data.PredicateTree P
1436 | on
1437 | (P.ParentID = T.ID) and
1438 | (P.Answer = T.Answer) and
1439 | (P.PredicateID = Q.PredicateID)
1440 | )
1441 | insert into @questionID(PredicateID, ID, New)
1442 | select PredicateID, ID, 0 from T
1443 | option(maxrecursion 0);
1444 |
1445 | if (@@rowcount >= @questionCount)
1446 | begin
1447 | break;
1448 | end;
1449 |
1450 | insert into @questionID(PredicateID, ID, New)
1451 | select
1452 | PredicateID,
1453 | next value for Data.PredicateTreeID over(order by PredicateID),
1454 | 1
1455 | from
1456 | @question
1457 | where
1458 | PredicateID not in (select PredicateID from @questionID);
1459 |
1460 | if (@@rowcount = 0)
1461 | begin
1462 | break;
1463 | end;
1464 |
1465 | begin try
1466 | with Q as
1467 | (
1468 | select
1469 | I.*, Q.Answer
1470 | from
1471 | @question Q
1472 | inner join
1473 | @questionID I
1474 | on
1475 | I.PredicateID = Q.PredicateID
1476 | ),
1477 | T as
1478 | (
1479 | select
1480 | ID,
1481 | lag(ID, 1, 0) over(order by PredicateID) ParentID,
1482 | lag(Answer, 1, 1) over(order by PredicateID) Answer,
1483 | PredicateID,
1484 | New
1485 | from
1486 | Q
1487 | )
1488 | insert into Data.PredicateTree(ID, ParentID, Answer, PredicateID, Populated)
1489 | select
1490 | ID, ParentID, Answer, PredicateID, 0
1491 | from
1492 | T
1493 | where
1494 | New = 1;
1495 |
1496 | break;
1497 | end try
1498 | begin catch
1499 | if (@debug = 1)
1500 | begin
1501 | print concat('Error: ', error_number(), '. ', error_message());
1502 | end;
1503 |
1504 | -- Cannot insert duplicate key row.
1505 | if (error_number() != 2601)
1506 | begin
1507 | throw;
1508 | end;
1509 |
1510 | delete from @questionID;
1511 | end catch;
1512 | end;
1513 |
1514 | declare @id int = null;
1515 | declare @answer decimal(2, 1) = null;
1516 |
1517 | if (@questionCount > 0)
1518 | begin
1519 | with Q as
1520 | (
1521 | select
1522 | I.*, Q.Answer
1523 | from
1524 | @question Q
1525 | inner join
1526 | @questionID I
1527 | on
1528 | I.PredicateID = Q.PredicateID
1529 | )
1530 | select top 1
1531 | @id = ID,
1532 | @answer = Answer
1533 | from
1534 | Q
1535 | order by
1536 | PredicateID desc;
1537 | end;
1538 |
1539 | if (@id is null)
1540 | begin
1541 | set @id = 0;
1542 | set @answer = 1;
1543 | end;
1544 |
1545 | if (@debug = 1)
1546 | begin
1547 | print concat('Tree ID: ', @id, ', answer: ', @answer);
1548 | end;
1549 |
1550 | set @retry = 2;
1551 |
1552 | while(@retry != 0)
1553 | begin
1554 | set @retry -= 1;
1555 |
1556 | declare @matches bit = null;
1557 |
1558 | with question as
1559 | (
1560 | select
1561 | T.Name name
1562 | from
1563 | Data.PredicateTree P
1564 | left join
1565 | Data.PredicateType T
1566 | on
1567 | T.PredicateID = P.PredicateID
1568 | where
1569 | (P.ParentID = @id) and
1570 | (P.Answer = @answer) and
1571 | (P.Populated = 1)
1572 | )
1573 | select
1574 | @result = (select * from question where name is not null for xml auto),
1575 | @matches = (select top 1 1 from question)
1576 |
1577 | if (@matches = 1)
1578 | begin
1579 | break;
1580 | end;
1581 |
1582 | create table #predicate
1583 | (
1584 | Weight decimal(5, 4) not null,
1585 | PredicateID hierarchyid not null,
1586 | Deviation decimal(2, 1),
1587 | primary key(Weight, PredicateID)
1588 | );
1589 |
1590 | declare @time1 datetime2(7) = current_timestamp;
1591 | declare @sql nvarchar(max) =
1592 | Dynamic.GetSQL_GetNextPredicate(@params) +
1593 | N'insert into #predicate(Weight, PredicateID, Deviation)
1594 | select top(@take) Weight, PredicateID, Deviation from R order by Weight desc, Deviation';
1595 |
1596 | declare @time2 datetime2(7) = current_timestamp;
1597 |
1598 | if (@debug = 1)
1599 | begin
1600 | print concat('SQL build time: ', datediff(millisecond, @time1, @time2), 'ms.');
1601 | print @sql;
1602 | end;
1603 |
1604 | execute sp_executesql @sql,
1605 | @params = N'@take int',
1606 | @take = @take;
1607 |
1608 | declare @matchCount int = @@rowcount;
1609 |
1610 | declare @time3 datetime2(7) = current_timestamp;
1611 |
1612 | if (@debug = 1)
1613 | begin
1614 | print concat('Execution time: ', datediff(millisecond, @time2, @time3), 'ms.');
1615 | end;
1616 |
1617 | set @retry = 2;
1618 |
1619 | while(@retry > 0)
1620 | begin
1621 | set @retry -= 1;
1622 |
1623 | begin try
1624 | with M as
1625 | (
1626 | select
1627 | dense_rank() over(order by Weight, Deviation) Rank,
1628 | PredicateID
1629 | from
1630 | #predicate
1631 | ),
1632 | P as
1633 | (
1634 | select
1635 | PredicateID
1636 | from
1637 | M
1638 | where
1639 | (Rank = 1) and
1640 | (@matchCount >= 2)
1641 | union all
1642 | select null where @matchCount < 2
1643 | ),
1644 | T as
1645 | (
1646 | select
1647 | *
1648 | from
1649 | Data.PredicateTree with(index(IX_PredicateTree))
1650 | where
1651 | (ParentID = @id) and
1652 | (Answer = @answer)
1653 | )
1654 | merge T
1655 | using P
1656 | on
1657 | (T.PredicateID = P.PredicateID) or
1658 | ((T.PredicateID is null) and (P.PredicateID is null))
1659 | when matched then
1660 | update set Populated = 1
1661 | when not matched by target then
1662 | insert(ParentID, Answer, PredicateID, Populated)
1663 | values(@id, @answer, P.PredicateID, 1)
1664 | when not matched by source then
1665 | delete;
1666 |
1667 | break;
1668 | end try
1669 | begin catch
1670 | if (@debug = 1)
1671 | begin
1672 | print concat('Error: ', error_number(), '. ', error_message());
1673 | end;
1674 |
1675 | -- Cannot insert duplicate key row.
1676 | if (error_number() != 2601)
1677 | begin
1678 | throw;
1679 | end;
1680 | end catch;
1681 | end;
1682 |
1683 | set @retry = 1;
1684 | end;
1685 | end;
1686 |
1687 | GO
1688 | SET ANSI_NULLS ON
1689 | GO
1690 | SET QUOTED_IDENTIFIER ON
1691 | GO
1692 | -- Invalidates a predicate. Either @predicateID or @name is required.
1693 | CREATE procedure [Data].[InvalidatePredicate]
1694 | (
1695 | -- A predicate id.
1696 | @predicateID hierarchyid = null,
1697 |
1698 | -- A predicate name.
1699 | @name nvarchar(128) = null,
1700 |
1701 | -- Debug indicator.
1702 | @debug bit = 0
1703 | )
1704 | as
1705 | begin
1706 | if (@debug = 0)
1707 | begin
1708 | set nocount on;
1709 | end;
1710 |
1711 | if (@predicateID is null)
1712 | begin
1713 | set @predicateID =
1714 | (select PredicateID from Data.PredicateType where Name = @name);
1715 | end;
1716 |
1717 | declare @sql nvarchar(max) =
1718 | N'insert into Data.Predicate(PredicateID, EntityID)
1719 | select distinct @predicateID, EntityID from ' +
1720 | (
1721 | select
1722 | Expression
1723 | from
1724 | Data.PredicateType
1725 | where
1726 | (Computed = 0) and
1727 | (PredicateID = @predicateID)
1728 | );
1729 |
1730 | if (@debug = 1)
1731 | begin
1732 | raiserror(@sql, 0, 1) with nowait;
1733 | end;
1734 |
1735 | declare @time1 datetime2(7) = current_timestamp;
1736 |
1737 | delete from Data.Predicate where PredicateID = @predicateID;
1738 |
1739 | execute sp_executesql @sql,
1740 | @params = N'@predicateID hierarchyid',
1741 | @predicateID = @predicateID;
1742 |
1743 | declare @time2 datetime2(7) = current_timestamp;
1744 |
1745 | if (@debug = 1)
1746 | begin
1747 | print concat('Execution time: ', datediff(millisecond, @time1, @time2), 'ms.');
1748 | end;
1749 |
1750 | execute Data.InvalidatePredicateTree;
1751 | end;
1752 |
1753 | GO
1754 | SET ANSI_NULLS ON
1755 | GO
1756 | SET QUOTED_IDENTIFIER ON
1757 | GO
1758 | -- Invalidates all predicates
1759 | create procedure [Data].[InvalidatePredicates]
1760 | (
1761 | @debug bit = 0
1762 | )
1763 | as
1764 | begin
1765 | set nocount on;
1766 |
1767 | declare @predicateID hierarchyid;
1768 |
1769 | declare Predicates cursor for
1770 | select
1771 | PredicateID
1772 | from
1773 | Data.PredicateType
1774 | where
1775 | (Expression is not null) and
1776 | (Computed = 0);
1777 |
1778 | open Predicates;
1779 |
1780 | fetch next from Predicates into @predicateID;
1781 |
1782 | while @@fetch_status = 0
1783 | begin
1784 | exec Data.InvalidatePredicate @predicateID = @predicateID, @debug = @debug;
1785 |
1786 | fetch next from Predicates into @predicateID;
1787 | end;
1788 |
1789 | close Predicates;
1790 | deallocate Predicates;
1791 | end;
1792 |
1793 | GO
1794 | SET ANSI_NULLS ON
1795 | GO
1796 | SET QUOTED_IDENTIFIER ON
1797 | GO
1798 | -- Invalidates a predicate. Either @predicateID or @name is required.
1799 | create procedure [Data].[InvalidatePredicateTree]
1800 | as
1801 | begin
1802 | begin transaction;
1803 | truncate table Data.PredicateTree;
1804 | alter sequence Data.PredicateTreeID restart with 1;
1805 | commit;
1806 | end;
1807 |
1808 | GO
1809 | SET ANSI_NULLS ON
1810 | GO
1811 | SET QUOTED_IDENTIFIER ON
1812 | GO
1813 | /*
1814 | declare @result xml;
1815 |
1816 | execute Data.PlaySearch @entityID = 5, @result = @result output;
1817 |
1818 | select @result;
1819 |
1820 | */
1821 |
1822 | -- Plays the search.
1823 | CREATE procedure [Data].[PlaySearch]
1824 | (
1825 | -- An entityID to search.
1826 | @entityID int,
1827 |
1828 | -- Maximum number of questions
1829 | @maxQuestions int = 30,
1830 |
1831 | -- Output response.
1832 | @result xml output,
1833 |
1834 | -- Use randomness while selecting new question.
1835 | @randomness bit = 0,
1836 |
1837 | -- Debug indicator.
1838 | @debug bit = 0
1839 | )
1840 | as
1841 | begin
1842 | set nocount on;
1843 |
1844 | declare @entityPredicate table
1845 | (
1846 | PredicateID hierarchyid not null primary key
1847 | );
1848 |
1849 | declare @currentPredicate table
1850 | (
1851 | ID int identity(1, 1),
1852 | PredicateID hierarchyid not null primary key,
1853 | Answer decimal(2, 1) not null
1854 | );
1855 |
1856 | insert into @entityPredicate(PredicateID)
1857 | select PredicateID from Data.Predicate where EntityID = @entityID;
1858 |
1859 | declare @i int = 0;
1860 |
1861 | while(@i <= @maxQuestions)
1862 | begin
1863 | set @i += 1;
1864 |
1865 | declare @params xml;
1866 |
1867 | with question as
1868 | (
1869 | select
1870 | C.ID,
1871 | T.Name,
1872 | C.Answer
1873 | from
1874 | @currentPredicate C
1875 | inner join
1876 | Data.PredicateType T
1877 | on
1878 | C.PredicateID = T.PredicateID
1879 | )
1880 | select
1881 | @params =
1882 | (
1883 | select
1884 | Name name,
1885 | Answer answer
1886 | from
1887 | question
1888 | order by
1889 | ID
1890 | for xml auto, root('request')
1891 | );
1892 |
1893 | declare @nextPredicate xml;
1894 |
1895 | execute Data.GetNextPredicates
1896 | @params = @params,
1897 | @result = @nextPredicate output,
1898 | @debug = @debug;
1899 |
1900 | if (@nextPredicate is null)
1901 | begin
1902 | break;
1903 | end;
1904 |
1905 | -- Select a predicate.
1906 | declare @predicateID hierarchyid =
1907 | (
1908 | select top 1
1909 | T.PredicateID
1910 | from
1911 | @nextPredicate.nodes('//question') N(Node)
1912 | inner loop join
1913 | Data.PredicateType T
1914 | on
1915 | T.Name = Node.value('@name', 'nvarchar(128)')
1916 | order by
1917 | case when @randomness = 1 then
1918 | iif(T.PredicateID in (select PredicateID from @entityPredicate), 0, 1)
1919 | end,
1920 | case when @randomness = 1 then newid() end,
1921 | T.PredicateID
1922 | );
1923 |
1924 | declare @answer decimal(2, 1) =
1925 | iif(@predicateID in (select PredicateID from @entityPredicate), 1, 0);
1926 |
1927 | insert into @currentPredicate(PredicateID, Answer)
1928 | values(@predicateID, @answer);
1929 | end;
1930 |
1931 | with question as
1932 | (
1933 | select
1934 | C.ID,
1935 | T.Name,
1936 | C.Answer
1937 | from
1938 | @currentPredicate C
1939 | inner join
1940 | Data.PredicateType T
1941 | on
1942 | C.PredicateID = T.PredicateID
1943 | )
1944 | select
1945 | @result =
1946 | (
1947 | select
1948 | Name name,
1949 | Answer answer
1950 | from
1951 | question
1952 | order by
1953 | ID
1954 | for xml auto, root('request')
1955 | );
1956 | end;
1957 |
1958 | GO
1959 |
1960 |
--------------------------------------------------------------------------------