perf: cache résultats de recherche par requête, invalidé sur create/update/delete
This commit is contained in:
+1
-1
@@ -8,6 +8,6 @@ vendor/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Fichiers uploadés et cache (propriété www-data)
|
||||
# Fichiers uploadés et cache générés (propriété www-data)
|
||||
data/*/files/
|
||||
data/_cache/
|
||||
|
||||
@@ -6,10 +6,15 @@
|
||||
"published": true,
|
||||
"published_at": "2026-06-08 07:00",
|
||||
"created_at": "2026-05-12 23:01:34",
|
||||
"updated_at": "2026-05-12 23:18:32",
|
||||
"updated_at": "2026-05-12 23:29:17",
|
||||
"revisions": [],
|
||||
"cover": "",
|
||||
"files_meta": [],
|
||||
"cover": "cover.jpg",
|
||||
"files_meta": {
|
||||
"cover.jpg": {
|
||||
"author": "",
|
||||
"source_url": ""
|
||||
}
|
||||
},
|
||||
"external_links": [
|
||||
{
|
||||
"url": "https://varlog.a5l.fr/post/post-install",
|
||||
@@ -24,6 +29,6 @@
|
||||
],
|
||||
"seo_title": "",
|
||||
"seo_description": "",
|
||||
"og_image": "",
|
||||
"og_image": "https://varlog.a5l.fr/file?uuid=0bba1ad7-e4cb-49a6-9467-fcfac2e09a93&name=cover.jpg",
|
||||
"category": "informatique"
|
||||
}
|
||||
|
||||
@@ -15,8 +15,19 @@
|
||||
"title": "Premiers pas DevOps : préparer un système Debian fraîchement installé"
|
||||
}
|
||||
],
|
||||
"cover": "",
|
||||
"files_meta": [],
|
||||
"cover": "cover.jpg",
|
||||
"files_meta": {
|
||||
"cover.jpg": {
|
||||
"author": "",
|
||||
"source_url": "https://3.bp.blogspot.com/-WER6d6fmIXU/WD1K9pOVoQI/AAAAAAAAGt4/47YWFQ7r7HQs2HTlkoz9KRt-1SmBXXaWwCLcB/s320/debian-logo.jpg",
|
||||
"title": "Logo Debian GNU Linux",
|
||||
"meta": {
|
||||
"mime": "image/jpeg",
|
||||
"size": 12823,
|
||||
"width": 320
|
||||
}
|
||||
}
|
||||
},
|
||||
"external_links": [],
|
||||
"seo_title": "",
|
||||
"seo_description": "",
|
||||
|
||||
File diff suppressed because one or more lines are too long
+10
-2
@@ -1854,9 +1854,13 @@ switch ($action) {
|
||||
$searchQuery = trim($_GET['q'] ?? '');
|
||||
$searchResults = [];
|
||||
if ($searchQuery !== '') {
|
||||
$isAnonSearch = !isLoggedIn();
|
||||
// Lecture du cache pour les visiteurs anonymes
|
||||
if ($isAnonSearch) {
|
||||
$searchResults = $articles->getSearchCache($searchQuery) ?? [];
|
||||
}
|
||||
if (empty($searchResults)) {
|
||||
$privateCats = $articles->getPrivateCategories();
|
||||
// Utilise l'index pré-construit si disponible (lecture d'un seul fichier JSON)
|
||||
// Sinon fallback sur getAll() qui scanne tous les répertoires
|
||||
$rawPool = $articles->getSearchIndex() ?? $articles->getAll(true);
|
||||
$searchPool = array_values(array_filter($rawPool, static function (array $a) use ($privateCats): bool {
|
||||
if (!($a['published'] ?? false)) {
|
||||
@@ -1872,6 +1876,10 @@ switch ($action) {
|
||||
return true;
|
||||
}));
|
||||
$searchResults = (new SearchEngine())->search($searchQuery, $searchPool);
|
||||
if ($isAnonSearch && !empty($searchResults)) {
|
||||
$articles->setSearchCache($searchQuery, $searchResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
include BASE_PATH . '/templates/search.php';
|
||||
break;
|
||||
|
||||
@@ -649,6 +649,53 @@ class ArticleManager
|
||||
$this->dataDir . '/search_index.json',
|
||||
json_encode($index, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
$this->clearSearchResultsCache();
|
||||
}
|
||||
|
||||
/** Vide le cache des résultats de recherche (appelé après chaque modification). */
|
||||
public function clearSearchResultsCache(): void
|
||||
{
|
||||
$dir = $this->dataDir . '/_cache/search';
|
||||
if (!is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
foreach (scandir($dir) as $f) {
|
||||
if (str_ends_with($f, '.json')) {
|
||||
@unlink($dir . '/' . $f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne les résultats mis en cache pour une requête anonyme, ou null si absent.
|
||||
* @return array<array>|null
|
||||
*/
|
||||
public function getSearchCache(string $query): ?array
|
||||
{
|
||||
$path = $this->searchCachePath($query);
|
||||
if (!file_exists($path)) {
|
||||
return null;
|
||||
}
|
||||
$data = json_decode((string) file_get_contents($path), true);
|
||||
return is_array($data) ? $data : null;
|
||||
}
|
||||
|
||||
/** Persiste les résultats d'une requête anonyme dans le cache. */
|
||||
public function setSearchCache(string $query, array $results): void
|
||||
{
|
||||
$dir = $this->dataDir . '/_cache/search';
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
file_put_contents(
|
||||
$this->searchCachePath($query),
|
||||
json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
}
|
||||
|
||||
private function searchCachePath(string $query): string
|
||||
{
|
||||
return $this->dataDir . '/_cache/search/' . md5(mb_strtolower(trim($query))) . '.json';
|
||||
}
|
||||
|
||||
/** Retourne l'index pré-construit, ou null s'il n'existe pas encore. */
|
||||
|
||||
Reference in New Issue
Block a user