Elasticsearch podstawowe operacje

Co mogę zrobić z Elasticsearch?

Zakładam, że wiesz, czym jest Elasticsearch:
https://jaroslawstadnicki.pl/2024/03/12/co-to-jest-elasticsearch/
Oraz że wiesz, jak go uruchomić:
https://jaroslawstadnicki.pl/2024/03/04/elasticsearch-i-docker/

Jak zacząć z tym pracować?

Zacznijmy od sprawdzenia, czy działa ping! Taki hello world dla Elasticsearch:

GET: http://localhost:9200

❗❗❗ W zależności od konfiguracji używaj http lub https

Jeśli świat nie zechce inaczej, to w wyniku powinno pokazać się
You know, for search

{
“name”: “22e9589dd825”,
“cluster_name”: “docker-cluster”,
“cluster_uuid”: “jUlehFZgRO-ibt6m5VKx6Q”,
“version”: {
“number”: “8.12.0”,
“build_flavor”: “default”,
“build_type”: “docker”,
“build_hash”: “1665f706fd9354802c02146c1e6b5c0fbcddfbc9”,
“build_date”: “2024-01-11T10:05:27.953830042Z”,
“build_snapshot”: false,
“lucene_version”: “9.9.1”,
“minimum_wire_compatibility_version”: “7.17.0”,
“minimum_index_compatibility_version”: “7.0.0”
},
“tagline”: “You Know, for Search
}

Gdzie baza?

Skoro to działa, to co mogę dalej? Gdzie bazy danych? Albo indeksy? Skoro to Elasticsearch;

GET: http://localhost:9200/_cat/indices?v

U mnie pojawia się taki pusty zapis:

health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size

Bo specjalnie dla Ciebie, usunąłem swój indeks i pokazuje co i jak wygląda na początku świata. Nie mam bazy danych i jak z tym żyć? Prościzna, wystarczy jeden strzał i już będzie:

PUT: http://localhost:9200/courses

(Tak, uwaga, tutaj jest PUT, sprawdź sam co odpowie Elasticsearch gdy zaproponujesz POSTa), w poprawnej odpowiedzi otrzymuje potwierdzenie:

{
    “acknowledged”: true,
    “shards_acknowledged”: true,
    “index”: “courses
}
Następnie ponownie zrobię pobranie indeksów:
GET: http://localhost:9200/_cat/indices?v
Będzie skutkowało teraz taką informacją:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open courses _JyXbuNdSlqPymuUQDL5tg 1 1 0 0 227b 227b 227b
Polecam robić to u lokalnie, formatowanie nie jest przyjazne dla długich linijek.
Usunięcie bazy, to prosty strzał:
DEL: http://localhost:9200/courses z odpowiedzią
Wynik:
{
    “acknowledged”: true
}
Odtworzę (PUT: http://localhost:9200/courses) indeks i mogę działać
ponownie.

Gdzie dane

Mam miejsce, gdzie mogę trzymać dane, to jak je tam teraz załadować? Czy to proste? Jak pisanie tego posta!
Wystarczy wykonać
POST: http://localhost:9200/courses/_doc

U mnie body wygląda w ten sposób:

{
    “name“: “elasticsearch i docker”,
    “description“: “Elasticsearch Jest to pierwszy z cyklu wpisów o Elasticsearch, opracowane na podstawie oficjalnej dokumentacji dostępnej pod linkiem: https://www.elastic.co/guide/en/elasticsearch/reference/8.12/docker.html W prywatnym projekcie, nad którym pracuje, do wyszukiwania kursów będę korzystać  narzędzia Elasticsearch. Ponieważ potrzebuje lepiej poznać to narzędzie, postanowiłem udokumentować kilka kroków z mojej podróży, aby dzielić się wiedzą, a jednocześnie liczę, że przyda się to także innym. Zamierzam korzystać z instalacji opartej o Docker i poniży wpis jest właśnie taką uproszczoną instrukcją jak tego dokonać.”
}

Dla lepszego efektu wykonam jeszcze jedną operację z takim body na ten sam url jak poprzednio:

{
    “name“: “co to jest elasticsearch”,
    “description“: “Czym jest elasticsearch? Sam elastisearch reklamuje się tym sloganem: You know, for search (and analysis) I generalnie tak jest, gdy myślę o szukaniu danych (wydajnym) to na myśl przychodzi mi właśnie Elasticsearch. Ale czekaj, bo to nie tylko szukanie – to znaczy i tak i nie, bo Elastic to coś więcej niż search, jest tam także Kibana, która ułatwia przeglądanie tego co mamy w bazie czy Logstash do wrzucania logów do tejże bazy. Ja, póki co skupiam się na Elasticsearch jako silniku do szukania, oprócz szukania potrafi też podać dodatkowe informacje dotyczące wyników; agregacje, statystyki, czy wyniki bliskie do tych, które są dla nas interesujące..”
}
Wyniki takich operacji wyglądają jakoś tak:
{
    “_index”: “courses”,
    “_id”: “QOTVb44BFw2yxe2y3POW”,
    “_version”: 1,
    “result”: “created”,
    “_shards”: {
        “total”: 2,
        “successful”: 1,
        “failed”: 0
    },
    “_seq_no”: 0,
    “_primary_term”: 1
}
Sprawdzam, czy są:
GET: http://localhost:9200/courses/_count
Czary:
{
    “count”: 2,
    “_shards”: {
        “total”: 1,
        “successful”: 1,
        “skipped”: 0,
        “failed”: 0
    }
}

Poka dane

Wygląda, że się zgadza! , gdzie szukanie? Selekt gwiazdka from students!
GET: http://localhost:9200/courses/_search
Muszę się ratować gistem, także:

Taki search “szuka” wszystkiego, co jest, można to ograniczać i zawężać wyniki, np:

http://localhost:9200/courses/_search?size=1&from=1

Ale gdyby tak poszukać czegoś konkretnego, warto wrzucić coś do body takiego zapytania, także robimy:
GET: http://localhost:9200/courses/_search

Z body ustawionym w taki sposób:

{
    “query”: {
        “simple_query_string”: {
            “query”: “co to jest elasticsearch”
        }
    }
}

Zwróci oba dokumenty, gdzie ten z takim właśnie tytułem będzie jako pierwszy, natomiast podmiana tego query na “elasticsearch i docker” – zmieni kolejnośc wyników – zwróć uwagę na pola:”max_score“: 3.9204745, oraz “_score“: 3.9204745 czy “_score“: 1.0661358. Warto także wrzucić w query to, co jest w opisie i zobaczyć czy szukanie też będzie działać – 🧝‍♂️

WHERE

Gdybyś chciał zawęzić pole wyszukiwania tylko do np. nazwy posta, można to zrobić modyfikując body w taki sposób:

{
    “query”: {
        “simple_query_string”: {
            “query”: “docker”,
            “fields“:[“name”]
        }
    }
}
Co spowoduje, że szukać będzie w name i nie zwróci już obu wyników.

Group by

Na koniec jeszcze grupowanie, bo to jest bardzo przydatna opcja. Aby lepiej pokazać wyniki dodałem, jeden dokument z takim samym tytułem — i jakimś krótkim opisem, a dodatkowo wyłączyłem szukanie, na potrzeby przejrzystego wyniku agregacji:

GET: http://localhost:9200/courses/_search

Body:
{
    “size”:0,
    “aggs”:{
        “names”:{
            “terms”:{
                “field”:”name.keyword”,
                “size”:10
            }
        }
    }
}
Rezultat:
Wynik zawiera informacje o agregowaniu na podstawie nazwy — co daje dwa dokumenty dla “elasticsearch i docker” (jeden, specjalnie dodany) oraz jeden dla “co to jest elasticsearch”.
Jeśli włączyć do tego wyszukiwanie, to agregowanie danych zostanie wykonane tylko na wynikach pasujących do zapytania:
{
    “size“:0,
    “query“: {
        “simple_query_string”: {
            “query”: “docker”,
            “fields”:[“name”]
        }
    },
    “aggs”:{
        “names”:{
            “terms”:{
                “field”:”name.keyword”,
                “size”:10
            }
        }
    }
}
W wypadku w agregacji dostanę tylko informacje o pasujących dokumentach, ale sam dokument nie zostanie wyświetlony — ponownie użyłem “size:0″.

Optymalizacja i selekcja danych

Na koniec jeszcze optymalizacja wyników, nie trzeba / nie powinno się ciągnąć pełnego dokumentu, dlatego można zawęzić się tylko do interesujących pól:
{
    “query”: {
        “simple_query_string”: {
            “query”: “docker”,
            “fields”:[“name”]
        }
    },
    “fields”:[“name”],
    “_source”:false
}
Zwróć uwagę na dodatkowe pole _source – sprawdź różnice w wynikach gdy usuniesz ten atrybut z body zapytania.
Od teraz potrafisz, tworzyć i usuwać bazy w elasticsearch, dodawać oraz szukać danych w swojej bazie opartej o Elasticsearch

co to jest elasticsearch

Czym jest elasticsearch?

Sam elastisearch reklamuje się tym sloganem:

You know, for search (and analysis)

I generalnie tak jest, gdy myślę o szukaniu danych (wydajnym) to na myśl przychodzi mi właśnie Elasticsearch. Ale czekaj, bo to nie tylko szukanie – to znaczy i tak i nie, bo Elastic to coś więcej niż search, jest tam także Kibana, która ułatwia przeglądanie tego co mamy w bazie czy Logstash do wrzucania logów do tejże bazy.
Ja, póki co skupiam się na Elasticsearch jako silniku do szukania, oprócz szukania potrafi też podać dodatkowe informacje dotyczące wyników; agregacje, statystyki, czy wyniki bliskie do tych, które są dla nas interesujące.

Continue reading

Logowanie dla leniwych

Nie lubię logowania

Nie lubię logowania — brudzi mi w kodzie; narzekam, gdy podczas ratowania produkcji brak logów — jak żyć?!

Jestem leniwy, nie lubię pamiętać o tym i tamtym — lubię, gdy rzeczy dzieją się same i nie muszę sobie zawracać tym głowy. Ale bez przesady! Logi to najgorsze i najlepsze co może spotkać programistów — z jednej strony logi zaśmiecają kod, z drugiej strony dają podgląd na to, co użytkownicy wymyślili na produkcji.

AOP

Logowanie przy pomocy AOP oczyszcza kod w przypadku typowego i klasycznego podejścia do logów, ok — może to zrobić. Często szukam w logach tego, co zostało uruchomione i z jakim parametrem, aby zrozumieć, co poszło nie tak. Nie lubię ^C^V takiego kodu na początku każdej metody. Niestety nie znalazłem dobrego rozwiązania AOP (czytaj darmowego) a interfejs IIntercept z jakiegoś powodu nie chce zostać uruchomiony (ale jest tworzony — kiedyś to zrozumiem); z tego powodu przy pomocy internetów znalazłem DispatchProxy które świetnie robi swoją robotę.

DispatchProxy

Otóż chciałbym mieć możliwość logowania tego, co i jak się wywołuje z możliwością włączenia / wyłączenia detali (poziomy logowania w moim przypadku, lub inna forma konfiguracji). Chce móc przeczytać logi i dowiedzieć się co się wywołuje i z jakim parametrami, dla każdej metody, dodatkowo bez potrzeby modyfikacji kodu, gdy dana metoda się zmieni.

Można to zrobić przy pomocy DispatchProxy które przechwyci wywołanie metody i umożliwi wykonanie dowolnego kodu; przed; po czy też podczas błędu.

Otóż taka klasa opina ładnie swoją docelową klasę T , a następnie podczas tworzenia zwraca takie proxy, udając klasę typu podstawowego. Tutaj uwaga: konstruktor musi być pusty, a ewentualne przekazanie parametrów i ich  przypisanie następuje w metody fabrykującej (wewnątrz if)

Gdy użytkownik takiej klasy wywołuje metodę docelową, na proxy wcześniej zostanie zawołane Invoke gdzie można czynić cuda.
Ja na przykład na poziomie `Information` loguje nazwę wywoływanej metody, a na poziomie Debug dorzucam także nazwy i wartości przekazanych argumentów.

Rejestracja

Piękne jest to, że DispatchProxy nie wymaga zewnętrznych bibliotek i działa na czysto z .net. Zależność do klasy rejestruje w taki sposób:

Akcja

Działa to tak:

Tutaj przykład konsumpcji oraz wykorzystania przykładowego serwisu

A tutaj logi:

Serwis jest nudny do bólu i prawie o nim zapomniałem:

Siup

W tak przygotowanym kodzie, zależności rejestrowane z pomocą logera powinny samodzielnie wrzucać informację o tym, co i jak się wykonało. Oczywiście można dodać sobie flagi do optymalizacji tego, czy przed, czy po co w sytuacjach wyjątkowych ma się logować i na jakim poziomie. Warto także pomyśleć o tym, jak takie logi ze sobą łączyć za pomocy correlationId – ale to pozostawiam już waszej wyobraźni.

 

ps.
dzisiaj bez obrazka

Wspólne modele dla dotnet i typescript

Trawa za płotem bardziej zielona

W Blazor’ze bardzo podoba mi się to, że brane są modele z dotnet (czy to api, czy to dowolna warstwa) i że każda zmiana na “backendzie” za darmo i od razu dostępna na “froncie”. Typescript ma fajne to, że można sobie silnie typować obiekty i że ten javascript jest takie ciut pewniejszy. Angular dla mnie mocno przypomina MVC więc z niego korzystam – ale! Jestem dobry w narzekanie; ale nie ma tego co ma blazor – a ja bym chciał. Bo takie przepisywanie modeli z dotnet na typescript to jest nudne, coś zmienisz, albo machniesz literówkę i trzeba szukać. Lubię też się wyręczać robotą kogoś innego 😉

google is your friend

Także poszukałem jak to ogarnąć. Co? No to, jak z klas w dotnet generować  klasy / kod do typescript, który można potem wykorzystać w projekcie na froncie.

Continue reading

Konfiguracja aplikacji

Konfiguracja aplikacji wydaje się być prosta, 😊 appsettings.json i jazda. Trochę tak, można trochę  więcej, bo przecież jest 🙂 azure key vault,
😅enviroment settings lokalnie, 😂enviroment settings na hoście,
😹appsettings.json.local, 😭appsettings.json.develop czy wreszcie
🤪Azure App Configuration.

Co wybrać jak żyć? To może po kolei 🚂

Continue reading