Czemu mój wpis na blogu jest wyżej

1

Pozycja na stronie głównej (/): #1
Data utworzenia: 11:36
Łapki: 2
Komentarze: 1
Godzina ostatniego komentarza: 14:29

a teraz wpis @Aleksander32

Pozycja na stronie głównej (/): #2
Data utworzenia: 11:11
Łapki: 10
Komentarze: 1
Godzina ostatniego komentarza: 14:27

wtf? czemu mój wpis jest wyżej?

wygląda to tak, jakby na stronie głównej były po prostu najnowsze wpisy pokazane

0

Też się jakiś czas temu zastanawiałem na jakiej zasadzie wpisy pojawiają się na stronie głównej i są pozycjonowane. Ktoś to robi ręcznie?

1

Tak na pierwszy rzut oka, to wydaje mi się, że poprzednio mikroblogi na głównej były generowane w ten sposób:

private function getMicroblogs()
{
	/** @var Builder $builder */
	$builder = app(Builder::class);

	$microblogs = $builder->orderByScore()->popular();

	MicroblogResource::withoutWrapping();

	return (new MicroblogCollection($microblogs))->resolve($this->request);
}

a teraz jest tak:

return view('homepage.whats-new', ['microblogs' => $this->microblog->recent()])->render();

public function recent()
{
	return $this->applyCriteria(function () {
		return $this->model->whereNull('parent_id')->withoutGlobalScope(UserRelationsScope::class)->limit(5)->orderBy('id', 'DESC')->get();
	});
}

czyli efektywnie straciliśmy orderByScore()->popular(); gdzie

/**
 * Pobierz X ostatnich wpisow z mikrobloga przy czym sortowane sa one wedlug oceny. Metoda
 * ta jest wykorzystywana na stronie glownej serwisu
 *
 * @param int $limit
 * @return mixed
 * @throws
 */
public function popular(int $limit)
{
	$this->applyCriteria();

	$result = $this
		->model
		->whereNull('parent_id')
		->with('user')
		->withCount('comments')
		->with('assets')
		->with('tags')
		->where(function (Builder $builder) {
			return $builder->where('votes', '>=', 2)->orWhere('is_sponsored', true);
		})
		->take($limit)
		->get();

	$this->resetModel();

	return $result;
}

chociaż, mój wpis na głównej pojawił się dopiero gdy dostał 2 łapkę, więc idk :D

2

Mówimy o stronie głównej serwisu, prawda? A nie zakładce mikroblogi? Na stronie głównej następuje sortowanie po kolumnie score. Wartość tej kolumny w tabeli ustalana jest tak:

log(liczba_glosow, 2) + (timestamp_wpisu / 45000)

1

@Adam Boduch:

Mówimy o stronie głównej serwisu, prawda?

no tak

że takie coś?

log(2, 2) + (1626514580 / 45000) = 36145.768444444444444444444444444444444444444444444444444444444444

log(10, 2) + (1626513080 / 45000) = 36145.036141106775092306324850005835604137879300992573219652421538

0

Nie sprawdzałem dokładnych obliczeń, ale chyba masz racje ;)

0

Muszę przyznać, że dość dziwna ta formułka, no ale wróćmy do w/w przykładu

czy takie zachowanie ma sens?

2 łapki
2h 57min od opublikowania

wyżej niż

10 łapek
3h 22min od opublikowania

0

Czy wybór takiego wzoru przypadkiem nie współgra z tym, co napisał @piotrpo w tym poście na temat właśnie sortowania wpisów na mikroblogu:

(…) [N]owy post pokaże się na początku wysoko, ma szansę złapać trochę punktów, jak nie nałapie ich dostatecznie dużo w jakimś tam czasie to zaczyna spadać.

1

@WeiXiao: Jak najbardziej możemy pomyśleć o zmianie tej formuły :) Rzeczywiście łapki powinny mieć większą "moc". Jaki wzór zatem proponujesz?

1

@Adam Boduch:

Właśnie nie wiem, przygotowałem sobie jakiś lab gdzie wstawiam ile łapek ma post oraz ile upłynęło godzin i próbuję coś sensownego ustrzelić

Muszę to w jakiś lepszy sposób zestawić, aby łatwiej było nad tym rozważać

np. w tym przykładzie jest dodane, aby mocniej karać wpisy mające >24h

https://dotnetfiddle.net/PtYLFe

public static void Main()
{
    var lapki = new List<int> { 1, 2, 3, 5, 10, 20, 25 };

    var godziny_od_utworzenia = new List<double> { 0.5, 1, 2, 4, 10, 20, 30, 48, 90 };

    Func<int, double, double> formula = (int lapki, double liczba_godziny_od_utworzenia) =>
    {
        var hourRatio = liczba_godziny_od_utworzenia > 24 ? 4 : 2;

        var result = lapki * 20 - (liczba_godziny_od_utworzenia * hourRatio);

        return result;
    };

    foreach (var lapka in lapki)
    {
        Console.WriteLine($"Łapki: {lapka}");
        foreach (var godzina in godziny_od_utworzenia)
        {
            Console.WriteLine($"\t Po {godzina}h = {formula(lapka, godzina)} pkt.");
        }
    }
}
Łapki: 1
         Po 0,5h = 19 pkt.
         Po 1h = 18 pkt.
         Po 2h = 16 pkt.
         Po 4h = 12 pkt.
         Po 10h = 0 pkt.
         Po 20h = -20 pkt.
         Po 30h = -100 pkt.
         Po 48h = -172 pkt.
         Po 90h = -340 pkt.
Łapki: 2
         Po 0,5h = 39 pkt.
         Po 1h = 38 pkt.
         Po 2h = 36 pkt.
         Po 4h = 32 pkt.
         Po 10h = 20 pkt.
         Po 20h = 0 pkt.
         Po 30h = -80 pkt.
         Po 48h = -152 pkt.
         Po 90h = -320 pkt.
Łapki: 3
         Po 0,5h = 59 pkt.
         Po 1h = 58 pkt.
         Po 2h = 56 pkt.
         Po 4h = 52 pkt.
         Po 10h = 40 pkt.
         Po 20h = 20 pkt.
         Po 30h = -60 pkt.
         Po 48h = -132 pkt.
         Po 90h = -300 pkt.
Łapki: 5
         Po 0,5h = 99 pkt.
         Po 1h = 98 pkt.
         Po 2h = 96 pkt.
         Po 4h = 92 pkt.
         Po 10h = 80 pkt.
         Po 20h = 60 pkt.
         Po 30h = -20 pkt.
         Po 48h = -92 pkt.
         Po 90h = -260 pkt.
Łapki: 10
         Po 0,5h = 199 pkt.
         Po 1h = 198 pkt.
         Po 2h = 196 pkt.
         Po 4h = 192 pkt.
         Po 10h = 180 pkt.
         Po 20h = 160 pkt.
         Po 30h = 80 pkt.
         Po 48h = 8 pkt.
         Po 90h = -160 pkt.
Łapki: 20
         Po 0,5h = 399 pkt.
         Po 1h = 398 pkt.
         Po 2h = 396 pkt.
         Po 4h = 392 pkt.
         Po 10h = 380 pkt.
         Po 20h = 360 pkt.
         Po 30h = 280 pkt.
         Po 48h = 208 pkt.
         Po 90h = 40 pkt.
Łapki: 25
         Po 0,5h = 499 pkt.
         Po 1h = 498 pkt.
         Po 2h = 496 pkt.
         Po 4h = 492 pkt.
         Po 10h = 480 pkt.
         Po 20h = 460 pkt.
         Po 30h = 380 pkt.
         Po 48h = 308 pkt.
         Po 90h = 140 pkt.

Tu mi się nie podoba, że ten wpis mający 25 łapek Po 48h nadal ma aż 408 pkt. a może to dobrze? bo przecież to tylko 2dni?

Albo w ogóle, co chcemy osiągnąć?

Czy wpisy z duża liczbą łapek mają utrzymywać się dłużej, np. kilka dni?

Albo czy nowe wpisy mają szybko wchodzić na główną?

@Silv

co sądzisz?

0

Nie mam preferencji co do wzoru. Jeśli masz już środowisko testowe – świetnie. :) Szybki sposób wyboru: wypróbuj dwa wzory różniące się zauważalnie od siebie i wybierzemy lepszy. Niech oba będą wyważone – w miarę intuicyjne.

Natomiast patrząc ogólnie, problem wygląda tak, że chcemy zoptymalizować co najmniej jedno kryterium, gdzie jedno kryterium to intuicja użytkowników. Mogą to być albo dwa kryteria (intuicja AND (łapki OR czas)), trzy (intuicja, łapki i czas), albo jeszcze więcej, jeśli by nam przyszły do głowy jakieś. Ja bym był za minimalną liczbą kryteriów, która jest intuicyjna (nomen-omen). Jeśli zechcemy mieć więcej lub mniej niż trzy, to proponowałbym przeprowadzić jakiś mniej lub bardziej formalny dowód, że trzy nie są dobre (np. pokazać, że któreś ekstremum występuje przy zbyt wielu wpisach zbyt często).


PS Oba wzory, o których wspomniałem w pierwszym akapicie, mogą się różnić od obecnego, jak też jeden z nich to może być obecny. Jeśli jesteśmy pewni, że obecny jest zły, to oba powinny być inne niż on.


UPDATE Zmieniłem opis, bo doszedłem do wniosku, że intuicja to także kryterium.

1
WeiXiao napisał(a):

Albo w ogóle, co chcemy osiągnąć?

Czy wpisy z duża liczbą łapek mają utrzymywać się dłużej, np. kilka dni?

Albo czy nowe wpisy mają szybko wchodzić na główną?

Na stronę główną wchodzą wpisy posiadające min. 2 głosy. Następnie następuje sortowanie po kolumnie score z tabeli microblogs.

Toteż kolumna ta musi zawierać wartość liczbową po której będziemy sortowali wszystkie wpisy. Czyli: SELECT * FROM microblogs WHERE votes >= 2 ORDER BY score DESC LIMIT 5.

Toteż data musi mieć tutaj istotny czynnik. Stare wpisy powinny z czasem tracić na znaczeniu mimo posiadania dużej liczby głosów.

W podanym przez Ciebie przykładzie rzeczywiście wpis posiadający 10 głosów powinien być wyżej niż ten posiadający 2 wpisy zakładając że obydwa wpisy są z tego samego dnia.

Inspiracją o ile pamiętam był stary algorytm reddita: https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9

Ale tu u nas wkradł się jakiś olbrzymi babol bo nowsze wpisy niemal zawsze będą miały wyższy ranking a głosy będą miały drugorzędne znaczenie :D

2

Taki pomysł na szybkości

Każda łapka daje 100 pkt.

Wpisy na mikro są widoczne powyżej 100pkt

Jeżeli wpis jest krócej* niż 16 godzin, to za każdą godzinę odejmuje się 10pkt
Jeżeli wpis jest krócej* niż 30 godzin, to za każdą godzinę odejmuje się 20pkt
Jeżeli wpis jest krócej* niż 48 godzin, to za każdą godzinę odejmuje się 30pkt

* - less or equal :)

Łapki: 1
         Po 0,5h = 95 pkt.

Tutaj sprawa jest prosta, nie wchodzi.

Łapki: 2
         Po 0,5h = 195 pkt.
         Po 1h = 190 pkt.
         Po 2h = 180 pkt.
         Po 4h = 160 pkt.
         Po 10h = 100 pkt.
         Po 20h = -200 pkt.

Wpis z 2 łapkami po 10h samoczynnie spadnie z głównej

Łapki: 3
         Po 0,5h = 295 pkt.
         Po 1h = 290 pkt.
         Po 2h = 280 pkt.
         Po 4h = 260 pkt.
         Po 10h = 200 pkt.
         Po 20h = -100 pkt.

Wpis z 3 łapkami po 17h samoczynnie spadnie z głównej

Łapki: 5
         Po 0,5h = 495 pkt.
         Po 1h = 490 pkt.
         Po 2h = 480 pkt.
         Po 4h = 460 pkt.
         Po 10h = 400 pkt.
         Po 20h = 100 pkt.

Wpis z 5 łapkami po 20h samoczynnie spadnie z głównej

Łapki: 10
         Po 0,5h = 995 pkt.
         Po 1h = 990 pkt.
         Po 2h = 980 pkt.
         Po 4h = 960 pkt.
         Po 10h = 900 pkt.
         Po 20h = 600 pkt.
         Po 32h = 40 pkt.

Wpis z 10 łapkami po 31h samoczynnie spadnie z głównej

Łapki: 20
         Po 0,5h = 1995 pkt.
         Po 1h = 1990 pkt.
         Po 2h = 1980 pkt.
         Po 4h = 1960 pkt.
         Po 10h = 1900 pkt.
         Po 20h = 1600 pkt.
         Po 32h = 1040 pkt.
         Po 49h = -450 pkt.
         Po 50h = -500 pkt.

Wpis z 20 łapkami po 49h samoczynnie spadnie z głównej

Łapki: 25
         Po 0,5h = 2495 pkt.
         Po 1h = 2490 pkt.
         Po 2h = 2480 pkt.
         Po 4h = 2460 pkt.
         Po 10h = 2400 pkt.
         Po 20h = 2100 pkt.
         Po 32h = 1540 pkt.
         Po 49h = 50 pkt.
         Po 50h = 0 pkt.

Wpis z 25 łapkami po 49h samoczynnie spadnie z głównej

No dobra, to teraz zestawmy z innymi wpisami jak to wygląda

np. w/w przypadek 10 vs 2 łapki

Liczba Łapek Liczba Godzin Suma Punktów
2 3 170
10 3.3 967
7 1 690
16 31 670
10 12 880
30 28 2440
15 10 1400
32 9 (wpis @p_agon teraz na blogu) 3110

Czyli dla w/w przypadku problem by się rozwiązał - 170 pkt vs 967.

Func<int, double, double> formula = (int lapki, double liczba_godzin_od_utworzenia) =>
{
    var basePoints = lapki * 100;

    var taxPerHour = liczba_godzin_od_utworzenia switch
    {
        _ when liczba_godzin_od_utworzenia <= 16 => 10,
        _ when liczba_godzin_od_utworzenia <= 30 => 20,
        _ when liczba_godzin_od_utworzenia <= 48 => 30,
        _ => 50
    };

    var tax = liczba_godzin_od_utworzenia * taxPerHour;

    return basePoints - tax;
};

Console.WriteLine(formula(10, 12));

Pytanie co zrobić jeżeli żaden wpis się nie będzie kwalifikował na główna? :P

2

Obecnie wartość po której sortowane są wpisy jest obliczana w momencie jego dodawania do bazy i zapisywana w kolumnie. Dzięki temu sortowanie jest szybsze niż liczenie tego na bieżąco. Ale ok, pomińmy na razie ten aspekt.

Testowałem sobie zapytanie SQL ze znacznie prostszym warunkiem: votes * 5 + (EXTRACT(EPOCH FROM microblogs.created_at::timestamp) - 1380153600) / 3600 desc

Jak widać mamy tutaj dwie wagi. Jedna to liczba głosów i wagą jest 5. Druga to czas. Timestamp wpisu po odjęciu 1380153600 (w przybliżeniu jest to timestamp 1 wpisu na mikroblogu). Dzielimy na 3600 i tutaj druga waga. Przy takim warunku wpisy na głównej wyglądałyby tak:

created_at votes substring
2021-07-28 1225 +00:00 15 Dzis jest dzień w którym pojawiło się ogłoszenie
2021-07-23 0616 +00:00 40 A jutro znów idziemy na całość! Miasto będzie pat
2021-07-22 0901 +00:00 43 gdy wydaje Ci sie, ze znasz juz kazdy model uzytk
2021-07-28 0627 +00:00 12 Objęliśmy patronatem ciekawy event, który wraca p
2021-07-27 1216 +00:00 14 Koniec pewnej epoki. Dziś serwis nasza klasa końc
2021-07-28 1156 +00:00 9 Drobna zmiana jeśli chodzi o widok mobilny listy

1 użytkowników online, w tym zalogowanych: 0, gości: 1