Commit 340fcc86 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

Merge branch '488-fehler-in-den-neuen-einstellungen' into 'development'

Suche funktioniert jetzt wieder auch für nicht eigene foki

Closes #488

See merge request !845
parents 9699a4e1 bd07b498
......@@ -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
{
......
......@@ -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())])));
......
......@@ -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;
}
......
......@@ -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());
}
}
......
......@@ -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)
{
......
......@@ -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;
}
}
......
......@@ -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;
}
});
}
/**
......
......@@ -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.',
];
......@@ -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>.",
];
......@@ -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.',
];
......@@ -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
......@@ -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>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment