├── 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 |
  1. The task should fit into SQL;
  2. 9 |
  3. The task is a good candidate for a neural network.
  4. 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 | 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 | 28 |

Having entities with properties we can:

29 | 34 |

Thus, the database should also contain following tables:

35 | 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 |
  1. Is sportsman? 49 |
      50 |
    1. Is football player?
    2. 51 |
    3. ...
    4. 52 |
    53 |
  2. 54 |
  3. Was born somewhere in Europe? 55 |
      56 |
    1. Was born in France?
    2. 57 |
    3. ...
    4. 58 |
    59 |
  4. 60 |
  5. ...
  6. 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |

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 | 606 |

How caching works

607 |

Caching is integrated into the procedure Data.GetNextPredicates.

608 |
    609 |
  1. 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.
  2. 610 |
  3. PredicateTree is checked to find a node that corresponds requested questions with answers.
  4. 611 |
  5. If such node is found then offered predicates are returned.
  6. 612 |
  7. Otherwise regular search is done, and results are cached into the PredicateTree.
  8. 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 | --------------------------------------------------------------------------------