-
Notifications
You must be signed in to change notification settings - Fork 20
/
boolean.php
106 lines (88 loc) · 3.59 KB
/
boolean.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?php
class Index {
private $index = array();
public function storeToken($documentId, $token) {
if( !isset($this->index[$token]) ) {
$this->index[$token] = array();
}
$this->index[$token][] = $documentId;
}
public function getPostings($token) {
return isset($this->index[$token]) ? $this->index[$token] : array();
}
}
class BooleanQuery {
private $index = 0;
private $tokens = array();
private $count;
private $tree;
public function __construct($query) {
preg_match_all('/[a-zA-Z]+|[\(\)]/', strtolower($query), $matches);
$this->count = count($matches[0]);
$this->tokens = $matches[0];
$this->tree = $this->buildQueryTree();
}
private function buildQueryTree() {
while($this->index < $this->count) {
$token = $this->tokens[$this->index];
$this->index++;
if('(' == $token) {
$tree = $this->buildQueryTree();
} else if(')' == $token) {
return $tree;
} else if(in_array($token, array('and', 'or', 'not'))) {
$tree = array('action' => $token, 'left' => $tree,
'right' => $this->buildQueryTree());
} else {
$tree = $token;
}
}
return $tree;
}
public function search($index) {
return $this->processQuery($this->tree, $index);
}
private function union($postings1, $postings2) {
return array_unique(array_merge($postings1, $postings2));
}
private function intersect($postings1, $postings2) {
return array_unique(array_intersect($postings1, $postings2));
}
private function complement($postings1, $postings2) {
return array_unique(array_diff($postings1, $postings2));
}
private function processQuery($queryTree, $index) {
if(is_array($queryTree)) {
$left = $this->processQuery($queryTree['left'], $index);
$right = $this->processQuery($queryTree['right'], $index);
switch($queryTree['action']) {
case 'and':
return $this->intersect($left, $right);
case 'or':
return $this->union($left, $right);
case 'not':
return $this->complement($left, $right);
}
} else {
return $index->getPostings($queryTree);
}
}
}
$index = new Index();
$documents = array(
"http://phpir.com/simple-searching-boolean-retrieval",
"http://phpir.com/presentation-tips-from-benelux",
"http://phpir.com/linear-regression-in-php-part-2",
);
foreach($documents as $documentID => $document) {
$contents = strtolower(strip_tags(file_get_contents($document)));
preg_match_all('/[a-zA-Z]+/', $contents, $matches);
$matches = array_unique($matches[0]);
foreach($matches as $match) {
$index->storeToken($documentID, $match);
}
unset($contents);
}
$query = 'PHP AND (Information OR Retrieval) NOT Spoons';
$q = new BooleanQuery($query);
var_dump($q->search($index));