diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 415cb73a7a94207aa549703409b741bb65bc83b3..21c9784cbd9a1dcbcef500101649a878978ba76f 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -5,8 +5,6 @@ namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; -use Illuminate\Http\Response; -use Predis\Connection\ConnectionException; class Handler extends ExceptionHandler { diff --git a/app/Http/Controllers/MetaGerSearch.php b/app/Http/Controllers/MetaGerSearch.php index 340951deb657a86d6793390339151fd48ef0ccb0..6ff189373365db4a7a7f34d18b59e28b59bac098 100644 --- a/app/Http/Controllers/MetaGerSearch.php +++ b/app/Http/Controllers/MetaGerSearch.php @@ -12,7 +12,7 @@ class MetaGerSearch extends Controller public function search(Request $request, MetaGer $metager) { $focus = $request->input("focus", "web"); - if ($focus !== "angepasst" && startsWith($focus, "focus_")) { + if ($focus !== "angepasst" && $this->startsWith($focus, "focus_")) { $metager->parseFormData($request); if ($metager->doBotProtection($request->input('bot', ""))) { return redirect(LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), url("/noaccess", ['redirect' => base64_encode(url()->full())]))); diff --git a/app/Jobs/Searcher.php b/app/Jobs/Searcher.php index 4ca6fda1d42de023a351c8c2310c967b9108732a..194a075362f13d5c12cb297e144855be9bd2e6e2 100644 --- a/app/Jobs/Searcher.php +++ b/app/Jobs/Searcher.php @@ -8,7 +8,6 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Support\Facades\Redis; -use Predis\Connection\ConnectionException; use Log; class Searcher implements ShouldQueue @@ -107,12 +106,6 @@ class Searcher implements ShouldQueue $result = curl_exec($this->ch); - if(!empty(curl_error($this->ch))){ - // Es gab einen Fehler beim Abruf des Ergebnisses - // diesen sollten wir protokollieren - Log::error("Fehler in der Searcher Klasse, beim Abruf des Ergebnisses: \n" . curl_error($this->ch)); - } - return $result; } diff --git a/app/MetaGer.php b/app/MetaGer.php index 2f7d913e0b40e34799a5ed4a7dfff6eba2157161..3730cf814275760142ac9ac63752b4fecc58607e 100644 --- a/app/MetaGer.php +++ b/app/MetaGer.php @@ -563,42 +563,35 @@ class MetaGer } # Wir starten alle Suchen - $success = true; foreach ($engines as $engine) { - if(!$engine->startSearch($this)){ - $success = false; - } + $engine->startSearch($this); } - if($success){ - // Derzeit deaktiviert, da es die eigene Suche gibt - // $this->adjustFocus($sumas, $enabledSearchengines); - - /* Wir warten auf die Antwort der Suchmaschinen - * Die Verbindung steht zu diesem Zeitpunkt und auch unsere Requests wurden schon gesendet. - * Wir zählen die Suchmaschinen, die durch den Cache beantwortet wurden: - * $enginesToLoad zählt einerseits die Suchmaschinen auf die wir warten und andererseits - * welche Suchmaschinen nicht rechtzeitig geantwortet haben. - */ - - $enginesToLoad = []; - $canBreak = false; - foreach ($engines as $engine) { - if ($engine->cached) { - if ($overtureEnabled && ($engine->name === "overture" || $engine->name === "overtureAds")) { - $canBreak = true; - } - } else { - $enginesToLoad[$engine->name] = false; + + // Derzeit deaktiviert, da es die eigene Suche gibt + // $this->adjustFocus($sumas, $enabledSearchengines); + + /* Wir warten auf die Antwort der Suchmaschinen + * Die Verbindung steht zu diesem Zeitpunkt und auch unsere Requests wurden schon gesendet. + * Wir zählen die Suchmaschinen, die durch den Cache beantwortet wurden: + * $enginesToLoad zählt einerseits die Suchmaschinen auf die wir warten und andererseits + * welche Suchmaschinen nicht rechtzeitig geantwortet haben. + */ + + $enginesToLoad = []; + $canBreak = false; + foreach ($engines as $engine) { + if ($engine->cached) { + if ($overtureEnabled && ($engine->name === "overture" || $engine->name === "overtureAds")) { + $canBreak = true; } + } else { + $enginesToLoad[$engine->name] = false; } + } - $this->waitForResults($enginesToLoad, $overtureEnabled, $canBreak); + $this->waitForResults($enginesToLoad, $overtureEnabled, $canBreak); - $this->retrieveResults($engines); - }else{ - Log::error('Fehler beim Verbindungsaufbau zum lokalen Redis Server!'); - $this->errors[] = trans('metager.redis.error'); - } + $this->retrieveResults($engines); } # Spezielle Suchen und Sumas @@ -822,13 +815,9 @@ class MetaGer { $timeStart = microtime(true); - $results = array(); + $results = null; while (true) { - try{ - $results = Redis::hgetall('search.' . $this->getHashCode()); - }catch(ConnectionException $e){ - break; - } + $results = Redis::hgetall('search.' . $this->getHashCode()); $ready = true; // When every @@ -1145,7 +1134,7 @@ class MetaGer public function rankAll() { foreach ($this->engines as $engine) { - $engine->rank($this->getQ(), $this->getPhrases()); + $engine->rank($this->getQ()); } } diff --git a/app/Models/Result.php b/app/Models/Result.php index 6dc1ad60f2608bfdeeba06e8d2d77dd11161497a..c60bf62f3178fac5ac4b24b5b35d06e0c634040a 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -72,9 +72,8 @@ class Result * + 0.02 * Sourcerank (20 - Position in Ergebnisliste des Suchanbieters) * * Engine-Boost */ - public function rank($eingabe, $phrases = []) - { - + public function rank($eingabe) + { $rank = 0; # Boost für Source Ranking @@ -96,11 +95,6 @@ class Result $rank -= $this->calcYandexBoost($eingabe); } - # Boost für Vorkommen der Suchwörter in der Beschreibung bei Phrasensuchen - if(!empty($phrases)) { - $rank += $this->calcPhraseSearchBoost($phrases); - } - $this->rank = $rank; } @@ -137,18 +131,6 @@ class Result return 0; } - # Berechnet den Ranking-Boost bei Phrasensuchen - private function calcPhraseSearchBoost($phrases) { - - $containsPhrase = true; - foreach($phrases as $phrase) { - if(strstr($this->longDescr, $phrase) == false) { - $containsPhrase = false; - } - } - return $containsPhrase ? 0.1 : 0; - } - # Berechnet den Ranking-Boost durch ??? URL public function calcURLBoost($tmpEingabe) { diff --git a/app/Models/Searchengine.php b/app/Models/Searchengine.php index 6fdfc2b8258ad20c189f75987670f5368f04b28f..eb26154c16f98ee096647e57f5b7568d7b94fb3c 100644 --- a/app/Models/Searchengine.php +++ b/app/Models/Searchengine.php @@ -8,7 +8,6 @@ use Cache; use Illuminate\Foundation\Bus\DispatchesJobs; use Log; use Illuminate\Support\Facades\Redis; -use Predis\Connection\ConnectionException; abstract class Searchengine { @@ -110,82 +109,76 @@ abstract class Searchengine $this->cached = true; $this->retrieveResults($metager); } else { - try{ - // We will push the confirmation of the submission to the Result Hash - Redis::hset('search.' . $this->resultHash, $this->name, "waiting"); - - // We need to submit a action that one of our workers can understand - // The missions are submitted to a redis queue in the following string format - // <ResultHash>;<URL to fetch> - // With <ResultHash> being the Hash Value where the fetcher will store the result. - // and <URL to fetch> being the full URL to the searchengine - $url = ""; - if($this->port === "443"){ - $url = "https://"; - }else{ - $url = "http://"; + // We will push the confirmation of the submission to the Result Hash + Redis::hset('search.' . $this->resultHash, $this->name, "waiting"); + // We need to submit a action that one of our workers can understand + // The missions are submitted to a redis queue in the following string format + // <ResultHash>;<URL to fetch> + // With <ResultHash> being the Hash Value where the fetcher will store the result. + // and <URL to fetch> being the full URL to the searchengine + $url = ""; + if($this->port === "443"){ + $url = "https://"; + }else{ + $url = "http://"; + } + $url .= $this->host . $this->getString; + $mission = $this->resultHash . ";" . $url; + // Submit this mission to the corresponding Redis Queue + // Since each Searcher is dedicated to one specific search engine + // each Searcher has it's own queue lying under the redis key <name>.queue + Redis::rpush($this->name . ".queue", $mission); + + /** + * We have Searcher processes running for MetaGer + * Each Searcher is dedicated to one specific Searchengine and fetches it's results. + * We can have multiple Searchers for each engine, if needed. + * At this point we need to decide, whether we need to start a new Searcher process or + * if we have enough of them running. + * The information for that is provided through the redis system. Each running searcher + * gives information how long it has waited to be given the last fetcher job. + * The longer this time value is, the less frequent the search engine is used and the less + * searcher of that type we need. + * But if it's too low, i.e. 100ms, then the searcher is near to it's full workload and needs assistence. + **/ + $needSearcher = false; + $searcherData = Redis::hgetall($this->name . ".stats"); + + // We now have an array of statistical data from the searchers + // Each searcher has one entry in it. + // So if it's empty, then we have currently no searcher running and + // of course need to spawn a new one. + if(sizeof($searcherData) === 0){ + $needSearcher = true; + }else{ + // There we go: + // There's at least one Fetcher running for this search engine. + // Now we have to check if the current count is enough to fetch all the + // searches or if it needs help. + // Let's hardcode a minimum of 100ms between every search job. + // First calculate the median of all Times + $median = 0; + foreach($searcherData as $pid => $data){ + $data = explode(";", $data); + $median += floatval($data[1]); } - $url .= $this->host . $this->getString; - $mission = $this->resultHash . ";" . $url; - // Submit this mission to the corresponding Redis Queue - // Since each Searcher is dedicated to one specific search engine - // each Searcher has it's own queue lying under the redis key <name>.queue - Redis::rpush($this->name . ".queue", $mission); - - /** - * We have Searcher processes running for MetaGer - * Each Searcher is dedicated to one specific Searchengine and fetches it's results. - * We can have multiple Searchers for each engine, if needed. - * At this point we need to decide, whether we need to start a new Searcher process or - * if we have enough of them running. - * The information for that is provided through the redis system. Each running searcher - * gives information how long it has waited to be given the last fetcher job. - * The longer this time value is, the less frequent the search engine is used and the less - * searcher of that type we need. - * But if it's too low, i.e. 100ms, then the searcher is near to it's full workload and needs assistence. - **/ - $needSearcher = false; - $searcherData = Redis::hgetall($this->name . ".stats"); - - // We now have an array of statistical data from the searchers - // Each searcher has one entry in it. - // So if it's empty, then we have currently no searcher running and - // of course need to spawn a new one. - if(sizeof($searcherData) === 0){ + $median /= sizeof($searcherData); + if($median < 100){ $needSearcher = true; - }else{ - // There we go: - // There's at least one Fetcher running for this search engine. - // Now we have to check if the current count is enough to fetch all the - // searches or if it needs help. - // Let's hardcode a minimum of 100ms between every search job. - // First calculate the median of all Times - $median = 0; - foreach($searcherData as $pid => $data){ - $data = explode(";", $data); - $median += floatval($data[1]); - } - $median /= sizeof($searcherData); - if($median < .1){ // Median is given as a float in seconds - $needSearcher = true; - } - } - if($needSearcher && Redis::get($this->name) !== "locked"){ - Redis::set($this->name, "locked"); - $this->dispatch(new Searcher($this->name)); } - return true; - }catch(ConnectionException $e){ - return false; + } + if($needSearcher && Redis::get($this->name) !== "locked"){ + Redis::set($this->name, "locked"); + $this->dispatch(new Searcher($this->name)); } } } # Ruft die Ranking-Funktion aller Ergebnisse auf. - public function rank($eingabe, $phrases = []) + public function rank($eingabe) { foreach ($this->results as $result) { - $result->rank($eingabe, $phrases); + $result->rank($eingabe); } } @@ -229,33 +222,28 @@ abstract class Searchengine # Fragt die Ergebnisse von Redis ab und lädt Sie public function retrieveResults(MetaGer $metager) { - try{ - if ($this->loaded) { - return true; - } - - $body = ""; - if ($this->canCache && $this->cacheDuration > 0 && Cache::has($this->hash) && 0 === 1) { - $body = Cache::get($this->hash); - } elseif (Redis::hexists('search.' . $this->resultHash, $this->name)) { - $body = Redis::hget('search.' . $this->resultHash, $this->name); - if ($this->canCache && $this->cacheDuration > 0 && 0 === 1) { - Cache::put($this->hash, $body, $this->cacheDuration); - } + if ($this->loaded) { + return true; + } + $body = ""; + if ($this->canCache && $this->cacheDuration > 0 && Cache::has($this->hash) && 0 === 1) { + $body = Cache::get($this->hash); + } elseif (Redis::hexists('search.' . $this->resultHash, $this->name)) { + $body = Redis::hget('search.' . $this->resultHash, $this->name); + if ($this->canCache && $this->cacheDuration > 0 && 0 === 1) { + Cache::put($this->hash, $body, $this->cacheDuration); } - if ($body !== "") { - $this->loadResults($body); - $this->getNext($metager, $body); - $this->loaded = true; - Redis::hdel('search.' . $this->hash, $this->name); - return true; - } else { - return false; - } - }catch(ConnectionException $e){ + + } + if ($body !== "") { + $this->loadResults($body); + $this->getNext($metager, $body); $this->loaded = true; + Redis::hdel('search.' . $this->hash, $this->name); return true; + } else { + return false; } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 448e39dbe076e1298accf6d0676b96cf0096e415..1e34cf8cd303acfb3b23198aeaa94dcf9ba75883 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -17,7 +17,40 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + # Wir loggen im Redis-System für jede Sekunde des Tages, wie viele Worker aktiv am Laufen waren. + # Dies ist notwendig, damit wir mitbekommen können, ab welchem Zeitpunkt wir zu wenig Worker zur Verfügung haben. + Queue::before(function (JobProcessing $event) { + $this->begin = strtotime(date(DATE_RFC822, mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y")))); + }); + Queue::after(function (JobProcessed $event) { + $today = strtotime(date(DATE_RFC822, mktime(0, 0, 0, date("m"), date("d"), date("Y")))); + $end = strtotime(date(DATE_RFC822, mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y")))) - $today; + $expireAt = strtotime(date(DATE_RFC822, mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")))); + try { + $redis = Redis::connection('redisLogs'); + if (!$redis) { + return; + } + + $p = getmypid(); + $host = gethostname(); + $begin = $this->begin - $today; + $redis->pipeline(function ($pipe) use ($p, $expireAt, $host, $begin, $end) { + for ($i = $begin; $i <= $end; $i++) { + $pipe->sadd("logs.worker.$host.$i", strval($p)); + $pipe->expire("logs.worker.$host.$i", 10); + $pipe->eval("redis.call('hset', 'logs.worker.$host', '$i', redis.call('scard', 'logs.worker.$host.$i'))", 0); + $pipe->sadd("logs.worker", $host); + if (date("H") !== 0) { + $pipe->expire("logs.worker.$host", $expireAt); + $pipe->expire("logs.worker", $expireAt); + } + } + }); + } catch (\Exception $e) { + return; + } + }); } /** diff --git a/resources/lang/de/faq.php b/resources/lang/de/faq.php index b7e845c95347ecf67b2fe2066d5910ee882e8cf5..ce6973fdb7e8554a99f7c54ec17ec26de4a6c80e 100644 --- a/resources/lang/de/faq.php +++ b/resources/lang/de/faq.php @@ -55,6 +55,4 @@ return [ 'faq.17.b.8' => '6. Dann gehen Sie auf die MetaGer-Startseite (https://metager.de/) und', 'faq.17.b.9' => '7. klicken auf den Button "MetaGer-Plugin hinzufügen" und folgen Sie bitte den Anweisungen dort.', 'faq.17.b.10' => 'Sie können MetaGer natürlich immer auch <em>ohne</em> Plugin benutzen, indem Sie in die Adresszeile Ihres Browsers "metager.de" eintippen.', - 'faq.18.h' => 'Warum werden !bangs nicht direkt geöffnet?', - 'faq.18.b' => 'Die !bang-„Weiterleitungen“ sind bei uns ein Teil unserer Quicktips und benötigen einen zusätzlichen „Klick“. Das war für uns eine schwierige Entscheidung, da die !bang dadurch weniger nützlich sind. Jedoch ist es leider nötig, da die Links, auf die weitergeleitet wird, nicht von uns stammen, sondern von einem Drittanbieter, DuckDuckGo.<p>Wir achten stehts darauf, dass unsere Nutzer jederzeit die Kontrolle behalten. Wir schützen daher auf zwei Arten: Zum Einen wird der eingegebene Suchbegriff niemals an DuckDuckGo übertragen, sondern nur das !bang. Zum Anderen bestätigt der Nutzer den Besuch des !bang-Ziels explizit. Leider können wir derzeit aus Personalgründen nicht alle diese !bangs prüfen oder selbst pflegen.', ]; diff --git a/resources/lang/de/hilfe.php b/resources/lang/de/hilfe.php index d42a360d37720c58ddfa8f94e1ad3d6c1f2f6ec7..f4522d6eb71acb5cbae0ebc47522a96815517438 100644 --- a/resources/lang/de/hilfe.php +++ b/resources/lang/de/hilfe.php @@ -75,6 +75,4 @@ return [ "maps.2" => "Die Karte zeigt nach dem Aufrufen die auch in der Spalte rechts wieder gegebenen von MetaGer gefundenen Punkte (POIs). Beim Zoomen passt sich die Liste an den Kartenausschnitt an. Wenn Sie die Maus über eine Markierung in der Karte oder in der Liste halten, wird das jeweilige Gegenstück hervorgehoben. Klicken Sie auf \"Details\", um genauere Informationen zu diesem Punkt aus der Nominatim-Datenbank zu erhalten.", "maps.3" => "Die Karten sind mit Ausnahme der drei letzten Zoomstufen vorgerendert und damit schnell verfügbar. Die Zoomstufe steuern Sie mit dem Mausrad oder mit den Plus-Minus-Buttons oben links in der Karte.", "sucheingabe" => "Sucheingabe", - "bang.title" => "!bangs", - "bang.1" => "MetaGer unterstützt in geringem Umfang eine Schreibweise, die oft als „!bang“-Syntax bezeichnet wird.<br>Ein solches „!bang“ beginnt immer mit einem Ausrufezeichen und enthält keine Leerzeichen. Beispiele sind hier „!twitter“ oder „!facebook“.<br>Wird ein !bang, das wir unterstützen, in der Suchanfrage verwendet, erscheint in unseren Quicktips ein Eintrag, über den man die Suche auf Knopfdruck mit dem jeweiligen Dienst (hier Twitter oder Facebook) fortführen kann.<p>Warum sich unser Vorgehen hier von anderen Anbietern unterscheidet lesen Sie in <a href=\"/faq/#bangs\" target=\"_blank\" rel=\"noopener\">unseren FAQ</a>.", ]; diff --git a/resources/lang/de/metaGer.php b/resources/lang/de/metaGer.php index 0339c2e790ba998ace737135ddda58e9a7d2fb18..e2baeb7c7bc4ae9de74c85f5ecd5559ee9ee8912 100644 --- a/resources/lang/de/metaGer.php +++ b/resources/lang/de/metaGer.php @@ -18,5 +18,4 @@ return [ 'sitesearch.failed' => 'Sie wollten eine Sitesearch auf :site durchführen. Leider unterstützen die eingestellten Suchmaschinen diese nicht. Sie können <a href=":searchLink">hier</a> die Sitesearch im Web-Fokus durchführen. Es werden ihnen Ergebnisse ohne Sitesearch angezeigt.', 'sitesearch.success' => 'Sie führen eine Sitesearch durch. Es werden nur Ergebnisse von der Seite: <a href="http://:site" target="_blank" rel="noopener">":site"</a> angezeigt.', - 'redis.error' => 'Aktuell treten bei uns leider technische Probleme auf. Bitte versuchen Sie es zu einem späteren Zeitpunkt erneut.', ]; diff --git a/resources/views/faq.blade.php b/resources/views/faq.blade.php index d579b682509c740fee12a28e294d9dc8e9db0abf..bf386c20363b687e47bdab7abb07217cac7a7a02 100644 --- a/resources/views/faq.blade.php +++ b/resources/views/faq.blade.php @@ -161,12 +161,4 @@ <p>{!! trans('faq.faq.17.b.10') !!}</p> </div> </div> - <div id="bangs" class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title">{!! trans('faq.faq.18.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.18.b') !!}</p> - </div> - </div> @endsection diff --git a/resources/views/hilfe.blade.php b/resources/views/hilfe.blade.php index 97b2159b88eef31f511aba37823dfcbdf37b5b6d..081b67c482124f6228b4d103ee027ea35627d71c 100644 --- a/resources/views/hilfe.blade.php +++ b/resources/views/hilfe.blade.php @@ -135,14 +135,6 @@ </div> </div> </div> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title">{!! trans('hilfe.bang.title') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('hilfe.bang.1') !!}</p> - </div> - </div> <h2 id="dienste">{!! trans('hilfe.dienste') !!}</h2> <div class="panel panel-default"> <div id="mg-app" style="margin-top: -100px"></div>