1
|
|
|
<?php declare(strict_types = 1); |
2
|
|
|
namespace ApacheSolrForTypo3\Solr\Domain\Search\Statistics; |
3
|
|
|
|
4
|
|
|
/*************************************************************** |
5
|
|
|
* Copyright notice |
6
|
|
|
* |
7
|
|
|
* (c) 2016 Thomas Hohn <[email protected]> |
8
|
|
|
* All rights reserved |
9
|
|
|
* |
10
|
|
|
* This script is part of the TYPO3 project. The TYPO3 project is |
11
|
|
|
* free software; you can redistribute it and/or modify |
12
|
|
|
* it under the terms of the GNU General Public License as published by |
13
|
|
|
* the Free Software Foundation; either version 3 of the License, or |
14
|
|
|
* (at your option) any later version. |
15
|
|
|
* |
16
|
|
|
* The GNU General Public License can be found at |
17
|
|
|
* http://www.gnu.org/copyleft/gpl.html. |
18
|
|
|
* |
19
|
|
|
* This script is distributed in the hope that it will be useful, |
20
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
21
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22
|
|
|
* GNU General Public License for more details. |
23
|
|
|
* |
24
|
|
|
* This copyright notice MUST APPEAR in all copies of the script! |
25
|
|
|
***************************************************************/ |
26
|
|
|
|
27
|
|
|
use ApacheSolrForTypo3\Solr\System\Records\AbstractRepository; |
28
|
|
|
use TYPO3\CMS\Core\Database\Query\QueryBuilder; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Calculates the SearchQueryStatistics |
32
|
|
|
* |
33
|
|
|
* @author Thomas Hohn <[email protected]> |
34
|
|
|
*/ |
35
|
|
|
class StatisticsRepository extends AbstractRepository |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* @var string |
39
|
|
|
*/ |
40
|
|
|
protected $table = 'tx_solr_statistics'; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Fetches must popular search keys words from the table tx_solr_statistics |
44
|
|
|
* |
45
|
|
|
* @param int $rootPageId |
46
|
|
|
* @param int $days number of days of history to query |
47
|
|
|
* @param int $limit |
48
|
|
|
* @return mixed |
49
|
|
|
*/ |
50
|
1 |
|
public function getSearchStatistics(int $rootPageId, int $days = 30, $limit = 10) |
51
|
|
|
{ |
52
|
1 |
|
$now = time(); |
53
|
1 |
|
$timeStart = (int)($now - 86400 * $days); // 86400 seconds/day |
54
|
1 |
|
$limit = (int)$limit; |
55
|
|
|
|
56
|
1 |
|
return $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords($rootPageId, $timeStart, $limit) |
|
|
|
|
57
|
1 |
|
->execute()->fetchAll(); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Returns prepared QueryBuilder for two purposes: |
62
|
|
|
* for getSearchStatistics() and getTopKeyWordsWithOrWithoutHits() methods |
63
|
|
|
* |
64
|
|
|
* @param int $rootPageId |
65
|
|
|
* @param int $timeStart |
66
|
|
|
* @param int $limit |
67
|
|
|
* @return QueryBuilder |
68
|
|
|
*/ |
69
|
4 |
|
protected function getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(int $rootPageId, int $timeStart, int $limit) : QueryBuilder |
70
|
|
|
{ |
71
|
4 |
|
$countRows = $this->countByRootPageId($rootPageId); |
72
|
4 |
|
$queryBuilder = $this->getQueryBuilder(); |
73
|
4 |
|
$statisticsQueryBuilder = $queryBuilder |
74
|
4 |
|
->select('keywords') |
75
|
4 |
|
->add('select', $queryBuilder->expr()->count('keywords', 'count'), true) |
76
|
4 |
|
->add('select', $queryBuilder->expr()->avg('num_found', 'hits'), true) |
77
|
4 |
|
->add('select', '(' . $queryBuilder->expr()->count('keywords') . ' * 100 / ' . $countRows . ') AS percent', true) |
78
|
4 |
|
->from($this->table) |
79
|
4 |
|
->andWhere( |
80
|
4 |
|
$queryBuilder->expr()->gt('tstamp', $timeStart), |
|
|
|
|
81
|
4 |
|
$queryBuilder->expr()->eq('root_pid', $rootPageId) |
82
|
|
|
) |
83
|
4 |
|
->groupBy('keywords') |
84
|
4 |
|
->orderBy('count', 'DESC') |
85
|
4 |
|
->addOrderBy('hits', 'DESC') |
86
|
4 |
|
->addOrderBy('keywords', 'ASC') |
87
|
4 |
|
->setMaxResults($limit); |
88
|
|
|
|
89
|
4 |
|
return $statisticsQueryBuilder; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Find Top search keywords with results |
94
|
|
|
* |
95
|
|
|
* @param int $rootPageId |
96
|
|
|
* @param int $days number of days of history to query |
97
|
|
|
* @param int $limit |
98
|
|
|
* @return array |
99
|
|
|
*/ |
100
|
1 |
|
public function getTopKeyWordsWithHits(int $rootPageId, int $days = 30, int $limit = 10) : array |
101
|
|
|
{ |
102
|
1 |
|
return $this->getTopKeyWordsWithOrWithoutHits($rootPageId, $days, $limit, false); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Find Top search keywords without results |
107
|
|
|
* |
108
|
|
|
* @param int $rootPageId |
109
|
|
|
* @param int $days number of days of history to query |
110
|
|
|
* @param int $limit |
111
|
|
|
* @return array |
112
|
|
|
*/ |
113
|
2 |
|
public function getTopKeyWordsWithoutHits(int $rootPageId, int $days = 30, int $limit = 10) : array |
114
|
|
|
{ |
115
|
2 |
|
return $this->getTopKeyWordsWithOrWithoutHits($rootPageId, $days, $limit, true); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Find Top search keywords with or without results |
120
|
|
|
* |
121
|
|
|
* @param int $rootPageId |
122
|
|
|
* @param int $days number of days of history to query |
123
|
|
|
* @param int $limit |
124
|
|
|
* @param bool $withoutHits |
125
|
|
|
* @return array |
126
|
|
|
*/ |
127
|
3 |
|
protected function getTopKeyWordsWithOrWithoutHits(int $rootPageId, int $days = 30, int $limit = 10, bool $withoutHits = false) : array |
128
|
|
|
{ |
129
|
3 |
|
$now = time(); |
130
|
3 |
|
$timeStart = $now - 86400 * $days; // 86400 seconds/day |
131
|
|
|
|
132
|
3 |
|
$queryBuilder = $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords($rootPageId, $timeStart, $limit); |
133
|
|
|
// Check if we want without or with hits |
134
|
3 |
|
if ($withoutHits === true) { |
135
|
2 |
|
$queryBuilder->andWhere($queryBuilder->expr()->eq('num_found', 0)); |
|
|
|
|
136
|
|
|
} else { |
137
|
1 |
|
$queryBuilder->andWhere($queryBuilder->expr()->gt('num_found', 0)); |
138
|
|
|
} |
139
|
|
|
|
140
|
3 |
|
return $queryBuilder->execute()->fetchAll(); |
|
|
|
|
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Get number of queries over time |
145
|
|
|
* |
146
|
|
|
* @param int $rootPageId |
147
|
|
|
* @param int $days number of days of history to query |
148
|
|
|
* @param int $bucketSeconds Seconds per bucket |
149
|
|
|
* @return array [labels, data] |
150
|
|
|
*/ |
151
|
|
|
public function getQueriesOverTime(int $rootPageId, int $days = 30, int $bucketSeconds = 3600) : array |
152
|
|
|
{ |
153
|
|
|
$now = time(); |
154
|
|
|
$timeStart = $now - 86400 * intval($days); // 86400 seconds/day |
155
|
|
|
|
156
|
|
|
$queryBuilder = $this->getQueryBuilder(); |
157
|
|
|
$result = $queryBuilder |
|
|
|
|
158
|
|
|
->addSelectLiteral( |
159
|
|
|
'FLOOR(tstamp/' . $bucketSeconds . ') AS bucket', |
160
|
|
|
'(tstamp - (tstamp % 86400)) AS timestamp', |
161
|
|
|
$queryBuilder->expr()->count('*', 'numQueries') |
162
|
|
|
) |
163
|
|
|
->from($this->table) |
164
|
|
|
->andWhere( |
165
|
|
|
$queryBuilder->expr()->gt('tstamp', $timeStart), |
|
|
|
|
166
|
|
|
$queryBuilder->expr()->eq('root_pid', $rootPageId) |
167
|
|
|
) |
168
|
|
|
->groupBy('bucket', 'timestamp') |
169
|
|
|
->orderBy('bucket', 'ASC') |
170
|
|
|
->execute()->fetchAll(); |
171
|
|
|
|
172
|
|
|
return $result; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Regurns a result set by given plugin.tx_solr.search.frequentSearches.select configuration. |
177
|
|
|
* |
178
|
|
|
* @param array $frequentSearchConfiguration |
179
|
|
|
* @return array Array of frequent search terms, keys are the terms, values are hits |
180
|
|
|
*/ |
181
|
|
|
public function getFrequentSearchTermsFromStatisticsByFrequentSearchConfiguration(array $frequentSearchConfiguration) : array |
182
|
|
|
{ |
183
|
|
|
$queryBuilder = $this->getQueryBuilder(); |
184
|
|
|
$resultSet = $queryBuilder |
|
|
|
|
185
|
|
|
->addSelectLiteral( |
186
|
|
|
$frequentSearchConfiguration['select.']['SELECT'] |
187
|
|
|
) |
188
|
|
|
->from($frequentSearchConfiguration['select.']['FROM']) |
189
|
|
|
->add('where', $frequentSearchConfiguration['select.']['ADD_WHERE'], true) |
190
|
|
|
->add('groupBy', $frequentSearchConfiguration['select.']['GROUP_BY'], true) |
191
|
|
|
->add('orderBy', $frequentSearchConfiguration['select.']['ORDER_BY']) |
192
|
|
|
->setMaxResults((int)$frequentSearchConfiguration['limit']) |
193
|
|
|
->execute()->fetchAll(); |
194
|
|
|
|
195
|
|
|
return $resultSet; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Persists statistics record |
200
|
|
|
* |
201
|
|
|
* @param array $statisticsRecord |
202
|
|
|
* @return void |
203
|
|
|
*/ |
204
|
1 |
|
public function saveStatisticsRecord(array $statisticsRecord) |
205
|
|
|
{ |
206
|
1 |
|
$queryBuilder = $this->getQueryBuilder(); |
207
|
1 |
|
$queryBuilder->insert($this->table)->values($statisticsRecord)->execute(); |
208
|
1 |
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Counts rows for specified site |
212
|
|
|
* |
213
|
|
|
* @param int $rootPageId |
214
|
|
|
* @return int |
215
|
|
|
*/ |
216
|
5 |
|
public function countByRootPageId(int $rootPageId): int |
217
|
|
|
{ |
218
|
5 |
|
$queryBuilder = $this->getQueryBuilder(); |
219
|
5 |
|
return (int)$this->getQueryBuilder() |
|
|
|
|
220
|
5 |
|
->count('*') |
221
|
5 |
|
->from($this->table) |
222
|
5 |
|
->andWhere($queryBuilder->expr()->eq('root_pid', $rootPageId)) |
|
|
|
|
223
|
5 |
|
->execute()->fetchColumn(0); |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.