Mundarija (26)
- Bu darsda
- 1. Nega bu kerak?
- 2. Asosiy tushunchalar
- 3. Mapping va analyzer
- 3.1 text va keyword
- 3.2 Analyzer zanjiri
- 4. Query DSL
- 4.1 match va term
- 4.2 bool: to'rt bo'lim
- 4.3 fuzziness: "AUTO"
- 5. Aggregation'lar
- 5.1 terms — facet'ning katta akasi
- 5.2 Taqsimlangan sanoqning narxi
- 6. Node.js klienti
- 7. Elasticsearch, OpenSearch va litsenziya
- 8. Resurs va operatsiya
- 9. Hujumchi nigohi
- 10. Ko'p uchraydigan xatolar
- 11. Mashqlar
- 1-mashq (oson): bo'shliqlarni to'ldiring
- 2-mashq (o'rta): date_histogram oyma-oy
- 3-mashq (qiyin): must_not va should qo'shing
- 12. Loyiha qadami: sinalmagan, loyihaga kirmaydi
- 13. Real ishda
- Xulosa
- Manbalar
Elasticsearch va OpenSearch: mapping, analyzer, query DSL va aggregation
Qisqacha: Elasticsearch — katta hajmdagi matn qidiruvi va loglar analitikasi uchun sanoat standarti, OpenSearch — uning 2021-yildagi ochiq kodli ayrilmasi (fork). Ikkalasida ham har maydonning turi mapping da beriladi (
text— qidiruv uchun tahlil qilinadi,keyword— aniq qiymat), so'rovlar JSON ko'rinishidagi query DSL da yoziladi (match,bool,fuzzy), sanoq va statistika esa aggregation lar bilan olinadi. Kuchli, lekin og'ir: kamida bir necha gigabayt xotira va jiddiy operatsion ish talab qiladi.
Bu darsda
- Mapping'da
textvakeywordfarqini va analyzer nima qilishini tushuntirasiz. - Query DSL'da
match,bool(must,filter,should,must_not) vafuzzinessni yozasiz. termsvadate_histogramaggregation'lari nimani qaytarishini bilasiz.@elastic/elasticsearchklienti bilan indekslash va qidiruv kodini o'qiysiz.- Elasticsearch, OpenSearch va Meilisearch orasida resurs va litsenziya bo'yicha tanlay olasiz.
Oldin bilishingiz kerak: Qidiruv tizimlari qanday ishlaydi, Meilisearch va Typesense, JSONB.
1. Nega bu kerak?
Meilisearch kichik va o'rta katalog uchun ajoyib. Lekin uchta vaziyatda boshqa vosita kerak bo'ladi.
Birinchisi — hajm. Yuz millionlab hujjat, bir nechta serverga bo'lingan indeks, server ishdan chiqsa ham ma'lumot yo'qolmasligi. Ikkinchisi — analitika. "Oxirgi 30 kunda har kuni nechta xato logi bo'ldi, qaysi servisdan?" — bu qidiruv emas, hisob-kitob. Uchinchisi — tahlil ustidan to'liq nazorat: har maydon uchun o'z tokenizatori, sinonimlar lug'ati, til qoidalari.
Bu ishlar uchun eng ko'p ishlatiladigan vosita — Elasticsearch. Uning ochiq kodli ayrilmasi — OpenSearch. Ikkalasi ham Apache Lucene kutubxonasi ustiga qurilgan — oldingi darslardagi inverted index va BM25'ning sanoat versiyasi.
Halol eslatma: bu dars sinalmagan. Kanon Elasticsearch va OpenSearch'ni ishga tushirmagan: image ~1 GB va 1–2 GB heap xotira talab qiladi, kanon mashinasida esa diskda joy kam edi. Shuning uchun darsdagi Elasticsearch kodi nocheck — u rasmiy hujjat bo'yicha yozilgan (2026-10), natijasi o'ylab topilmaydi. Brauzerda ishlaydigan bloklar esa — dvigatel ichidagi g'oyalarni JavaScript'da takrorlaydi, ularning chiqishi haqiqiy.
2. Asosiy tushunchalar
| Elasticsearch | Ma'nosi | Meilisearch'da |
|---|---|---|
| indeks (index) | hujjatlar to'plami | indeks |
| hujjat (document) | JSON obyekt, _id bilan |
hujjat |
| mapping | maydonlar turi va tahlili | sozlamalar |
| shard | indeksning bo'lagi (alohida Lucene indeksi) | yo'q |
| replica | shard nusxasi, boshqa serverda | yo'q |
| node, cluster | bitta server, serverlar guruhi | asosan bitta |
Shard va replica — Elasticsearch'ning masshtablash g'oyasi. Indeks bir nechta bo'lakka bo'linadi, bo'laklar turli serverlarga tarqatiladi. So'rov hamma bo'laklarga parallel yuboriladi, natijalar birlashtiriladi. Replica esa bo'lakning nusxasi: bitta server o'chsa, nusxasi javob beradi.
flowchart TB
Q["So'rov"] --> N1
Q --> N2
subgraph N1["Server 1"]
S0["shard 0"]
R1["replica 1"]
end
subgraph N2["Server 2"]
S1["shard 1"]
R0["replica 0"]
end
S0 -.nusxa.-> R0
S1 -.nusxa.-> R1Diagrammada indeks ikki shard'ga bo'lingan va har shard'ning nusxasi boshqa serverda. 1-server o'chsa, 0-shard ma'lumoti 2-serverdagi replica'dan o'qiladi.
3. Mapping va analyzer
3.1 text va keyword
Mapping — indeksning sxemasi. Eng muhim farq — satr maydonining ikki turi:
text— qidiruv uchun. Saqlashdan oldin analyzer'dan o'tadi: so'zlarga bo'linadi, kichik harfga keltiriladi."Kitob O'qish"→kitob,o'qish.matchso'rovi bilan qidiriladi.keyword— aniq qiymat uchun. Tahlil qilinmaydi:"yuqori"qanday bo'lsa shunday. Filtr, saralash va aggregation uchun.
Bitta maydon ikkalasi bo'lishi mumkin — multi-field. Hujjatga ko'ra mapping shunday yoziladi:
const mapping = {
properties: {
matn: {
type: "text",
analyzer: "uz_matn",
fields: { aniq: { type: "keyword", ignore_above: 256 } },
},
egasi: { type: "integer" },
ustuvorlik: { type: "keyword" },
bajarildi: { type: "boolean" },
yaratilgan: { type: "date" },
},
};matn — qidiruv uchun, matn.aniq — aniq tenglik va saralash uchun. Mapping'ni oldindan bermasangiz, Elasticsearch birinchi hujjatdan turini o'zi taxmin qiladi (dynamic mapping). Satrni u sukut bo'yicha text + keyword multi-field qiladi. Qulay, lekin xavfli: "42" satri kelsa, maydon satr bo'lib qoladi, keyin son kelsa ham. Mavjud maydon turini o'zgartirib bo'lmaydi — yangi indeks yaratib, ma'lumotni ko'chirish (reindex) kerak.
Diqqat: Production indeksida mapping'ni doim qo'lda bering. Turni tuzatish — butun indeksni qayta yozish degani.
3.2 Analyzer zanjiri
Analyzer — Qidiruv tizimlari qanday ishlaydi darsidagi "tokenizatsiya → normallash → stemming" zanjirining Elasticsearch'dagi nomi. U uch qismdan iborat:
- Character filter — matnni tokenizatsiyadan oldin o'zgartiradi (masalan
‘→'). - Tokenizer — so'zlarga bo'ladi (sukut
standard— Unicode qoidalari bo'yicha). - Token filter — har tokenni o'zgartiradi:
lowercase,asciifolding(é→e),stop(keraksiz so'zlar), sinonimlar, stemming.
O'zbek tili uchun tayyor analyzer yo'q. Hujjatga ko'ra o'zingiznikini yig'asiz — apostroflarni bitta belgiga keltiradigan mapping character filter va lowercase bilan:
const settings = {
analysis: {
char_filter: {
apostrof: {
type: "mapping",
mappings: ["‘ => '", "’ => '", "ʻ => '", "ʼ => '"],
},
},
analyzer: {
uz_matn: {
type: "custom",
char_filter: ["apostrof"],
tokenizer: "standard",
filter: ["lowercase"],
},
},
},
};Bu zanjir nima qilishini JavaScript'da takrorlab ko'ramiz. Elasticsearch har tokenning pozitsiyasini ham saqlaydi — "so'zlar yonma-yon turibdimi" (match_phrase) shunga kerak:
const APOSTROF = /[‘’ʻʼ]/g;
function tahlil(matn) {
const tozalangan = matn.replace(APOSTROF, "'");
const tokenlar = tozalangan.match(/[\p{L}\p{N}']+/gu) ?? [];
return tokenlar.map((t, pozitsiya) => ({
token: t.toLowerCase(),
pozitsiya,
}));
}
console.log(tahlil("Kitob O‘qish: har kuni 20 bet"));Konsolda:
[
{ token: 'kitob', pozitsiya: 0 },
{ token: "o'qish", pozitsiya: 1 },
{ token: 'har', pozitsiya: 2 },
{ token: 'kuni', pozitsiya: 3 },
{ token: '20', pozitsiya: 4 },
{ token: 'bet', pozitsiya: 5 }
]\p{L} — har qanday tildagi harf (Unicode regex), shuning uchun kirill so'zlar ham token bo'ladi. Haqiqiy standard tokenizer bundan murakkabroq (Unicode so'z chegaralari qoidasi), lekin g'oya shu.
Elasticsearch'da analyzer'ni _analyze API bilan sinash mumkin — mapping yozishdan oldin har doim shunday qiling. Oldingi darsda ko'rganimizdek, hujjat va so'rov bitta analyzer'dan o'tishi shart. Elasticsearch buni o'zi ta'minlaydi: match so'rovi maydon analyzer'ini so'rov matniga ham qo'llaydi.
4. Query DSL
4.1 match va term
Query DSL — so'rov tili, JSON ko'rinishida. Ikkita asosiy so'rov:
match—textmaydon uchun. So'rov matnini analyzer'dan o'tkazadi, keyin BM25 bilan saralaydi.term—keyword, son, boolean uchun. Tahlilsiz, aniq tenglik.
Klassik xato: text maydonga term so'rovi. Hujjatda "Kitob" saqlangan, indeksda esa kitob (kichik harf). term: { matn: "Kitob" } hech narsa topmaydi — chunki term so'rov matnini tahlil qilmaydi.
4.2 bool: to'rt bo'lim
Murakkab so'rov bool bilan yig'iladi:
| Bo'lim | Ma'nosi | Ballga ta'siri |
|---|---|---|
must |
shart, bajarilishi kerak | qo'shiladi |
filter |
shart, bajarilishi kerak | yo'q, natija keshlanadi |
should |
bajarilsa — yaxshi | qo'shiladi |
must_not |
bajarilmasligi kerak | yo'q |
Qoida: ball kerak bo'lmagan hamma shart — filter ga. "Egasi 7", "bajarilmagan", "ustuvorlik yuqori" — bular "qanchalik mos" emas, "mos yoki yo'q". filter ball hisoblamaydi va natijasini keshlaydi — tezroq. Foydalanuvchi so'zi esa must ga, chunki u saralashni belgilaydi.
So'rovni yig'adigan funksiya — oddiy JavaScript, uni brauzerda sinaymiz:
const USTUVORLIK = new Set(["past", "orta", "yuqori"]);
function sorovYasa(egasiId, { q, ustuvorlik, bajarildi }) {
const filter = [{ term: { egasi: egasiId } }];
if (ustuvorlik && USTUVORLIK.has(ustuvorlik)) {
filter.push({ term: { ustuvorlik } });
}
if (bajarildi === "true" || bajarildi === "false") {
filter.push({ term: { bajarildi: bajarildi === "true" } });
}
const must = q
? [{ match: { matn: { query: q, fuzziness: "AUTO" } } }]
: [{ match_all: {} }];
return { query: { bool: { must, filter } } };
}
const s = sorovYasa(7, { q: "kitb oqish", bajarildi: "false" });
console.log(JSON.stringify(s, null, 1));Konsolda:
{
"query": {
"bool": {
"must": [
{
"match": {
"matn": {
"query": "kitb oqish",
"fuzziness": "AUTO"
}
}
}
],
"filter": [
{
"term": {
"egasi": 7
}
},
{
"term": {
"bajarildi": false
}
}
]
}
}
}Meilisearch'dagi filtr matnidan farqli, bu yerda so'rov — JSON obyekt. Foydalanuvchi qiymati satr ichiga yopishtirilmaydi, alohida maydon bo'lib ketadi — matnli in'eksiya xavfi kamroq. Lekin ruxsat ro'yxati baribir kerak: aks holda foydalanuvchi mavjud bo'lmagan qiymat bilan bo'sh natija oladi yoki siz kutmagan maydonga filtr qo'yadi.
4.3 fuzziness: "AUTO"
fuzziness — typo tolerance. "AUTO" qiymati hujjatga ko'ra so'z uzunligiga qarab ruxsat beradi: 1–2 belgi — xato yo'q, 3–5 belgi — bitta, 6 va undan ko'p — ikkita. Oldingi darsdagi ruxsat() funksiyasining o'zi, faqat chegaralari boshqa:
function auto(soz) {
if (soz.length <= 2) return 0;
if (soz.length <= 5) return 1;
return 2;
}
for (const s of ["ok", "kitb", "oqish", "hisobt", "dorixna"]) {
console.log(s, s.length, "→", auto(s), "ta xato");
}Konsolda:
ok 2 → 0 ta xato
kitb 4 → 1 ta xato
oqish 5 → 1 ta xato
hisobt 6 → 2 ta xato
dorixna 7 → 2 ta xatoAlohida fuzzy so'rovi ham bor — u bitta termni tahlilsiz, belgilangan masofa bilan qidiradi. Amalda match + fuzziness qulayroq: tahlil ham, typo ham bir joyda.
5. Aggregation'lar
5.1 terms — facet'ning katta akasi
Aggregation — natija ustidan hisob: sanoq, yig'indi, o'rtacha, guruhlash. Qidiruv va hisob bitta so'rovda keladi. Hujjatga ko'ra so'rov shunday:
const javob = await es.search({
index: "vazifalar",
query: { bool: { filter: [{ term: { egasi: 7 } }] } },
size: 0,
aggs: {
ustuvorlik: { terms: { field: "ustuvorlik" } },
oylar: {
date_histogram: {
field: "yaratilgan",
calendar_interval: "month",
},
},
},
});size: 0 — hujjatlarning o'zi kerak emas, faqat hisob. terms — maydon qiymatlari bo'yicha guruh va har guruhdagi hujjatlar soni (Meilisearch'dagi facet). date_histogram — vaqt oralig'i bo'yicha guruh. Aggregation faqat keyword, son va sana maydonlarida ishlaydi — text da emas. Mapping'da ustuvorlik ni keyword qilganimiz shuning uchun.
Natija tuzilmasi — aggregations.ustuvorlik.buckets massivi, har bucket'da key va doc_count. Mantiqni JavaScript'da takrorlaymiz:
const hujjatlar = [
{ ustuvorlik: "yuqori", yaratilgan: "2026-09-14" },
{ ustuvorlik: "orta", yaratilgan: "2026-09-30" },
{ ustuvorlik: "yuqori", yaratilgan: "2026-10-02" },
{ ustuvorlik: "past", yaratilgan: "2026-10-11" },
{ ustuvorlik: "yuqori", yaratilgan: "2026-10-27" },
];
function terms(royxat, maydon) {
const sanoq = new Map();
for (const h of royxat) {
sanoq.set(h[maydon], (sanoq.get(h[maydon]) ?? 0) + 1);
}
return [...sanoq]
.map(([key, doc_count]) => ({ key, doc_count }))
.sort((a, b) => b.doc_count - a.doc_count);
}
console.log(terms(hujjatlar, "ustuvorlik"));Konsolda:
[
{ key: 'yuqori', doc_count: 3 },
{ key: 'orta', doc_count: 1 },
{ key: 'past', doc_count: 1 }
]Elasticsearch ham bucket'larni sukut bo'yicha doc_count kamayishi tartibida va faqat birinchi 10 tasini qaytaradi (size bilan o'zgaradi).
5.2 Taqsimlangan sanoqning narxi
Indeks shard'larga bo'lingan bo'lsa, terms har shard'da alohida hisoblanadi, keyin birlashtiriladi. Har shard faqat o'zining "eng ko'p" qiymatlarini yuboradi. Natijada kam uchraydigan qiymat sanog'i taxminiy bo'lishi mumkin — hujjat bu xatoni doc_count_error_upper_bound maydonida ko'rsatadi. Bitta shard'li indeksda bu muammo yo'q. Bu — taqsimlangan tizimning odatiy narxi: tezlik uchun aniqlikdan biroz voz kechish.
Tekshirib ko'ring: Nega
matn(text) maydoni bo'yichatermsaggregation qilib bo'lmaydi?
Javob
text maydon so'zlarga bo'lingan — indeksda butun qiymat emas, alohida tokenlar bor. Elasticsearch sukut bo'yicha text uchun aggregation'ni rad etadi (fielddata o'chiq), chunki tokenlar bo'yicha sanoq ko'p xotira oladi va odatda kerakli narsa emas. Butun qiymat bo'yicha sanash kerak bo'lsa — matn.aniq (keyword multi-field).
6. Node.js klienti
Rasmiy klient — @elastic/elasticsearch. Uning katta versiyasi server versiyasiga mos bo'lishi kerak (9.x server — 9.x klient). Hujjat bo'yicha indeks yaratish, hujjat yuklash va qidirish:
import { Client } from "@elastic/elasticsearch";
const es = new Client({
node: process.env.ES_URL,
auth: { apiKey: process.env.ES_API_KEY },
});
await es.indices.create({
index: "vazifalar",
settings,
mappings: mapping,
});
await es.helpers.bulk({
datasource: vazifalar,
onDocument: (v) => ({
index: { _index: "vazifalar", _id: String(v.id) },
}),
});
const r = await es.search({
index: "vazifalar",
...sorovYasa(7, { q: "kitob" }),
});
for (const hit of r.hits.hits) {
console.log(hit._score, hit._source.matn);
}Uch narsa e'tiborga loyiq:
helpers.bulk— minglab hujjatni bitta-bitta emas, to'plab yuboradi (_bulkAPI). 50 000 hujjatni bittadan yuborish — 50 000 HTTP so'rov.- Refresh — yuklangan hujjat qidiruvda darhol ko'rinmaydi. Elasticsearch indeksni sukut bo'yicha har soniyada yangilaydi (
refresh_interval). Bu — Meilisearch'dagi asinxron task bilan bir xil g'oya: "near real-time". - API kalit —
ES_API_KEYserver env'ida. Elasticsearch brauzerga ochiladigan xizmat emas, unda Meilisearch'dagi kabi tenant token yo'q. Qidiruv doim backend orqali.
OpenSearch'ning klienti alohida — @opensearch-project/opensearch. Asosiy API o'xshash, lekin ikkala klient almashinmaydi: har biri o'z serveri bilan ishlaydi.
7. Elasticsearch, OpenSearch va litsenziya
Tarixni qisqa aytamiz — u tanlovga ta'sir qiladi:
- Elasticsearch uzoq vaqt Apache 2.0 litsenziyasida edi.
- 2021-yilda Elastic litsenziyani SSPL va Elastic License 2.0 ga almashtirdi. Sabab — bulut provayderlari uni xizmat sifatida sotayotgan edi.
- Shunga javoban AWS oxirgi Apache versiyasidan (7.10.2) ayrilma yaratdi — OpenSearch, Apache 2.0 litsenziyasida.
- 2024-yil 29-avgustda Elastic AGPL'ni uchinchi litsenziya varianti sifatida qo'shdi.
- 2024-yil sentyabrda OpenSearch Linux Foundation qoshidagi OpenSearch Software Foundation'ga o'tkazildi.
Bugun ikkalasi alohida rivojlanmoqda: API'larning asosiy qismi mos, lekin yangi imkoniyatlar (vektor qidiruv, xavfsizlik, ML) farq qiladi. Kodni ikkalasiga birdan yozmang — bittasini tanlang.
| Elasticsearch | OpenSearch | Meilisearch | |
|---|---|---|---|
| Litsenziya | ELv2 / SSPL / AGPL | Apache 2.0 | MIT (asosiy versiya) |
| Kuchli tomoni | qidiruv + analitika, ekotizim (Kibana) | AWS'da boshqariladigan xizmat | soddalik, typo tolerance |
| Xotira | gigabaytlar (JVM heap) | gigabaytlar (JVM heap) | kamroq |
| O'rganish | qiyin | qiyin | oson |
8. Resurs va operatsiya
Elasticsearch — JVM (Java) ilovasi. Hujjatga ko'ra heap hajmi mashina xotirasining yarmidan oshmasligi kerak — qolgani operatsion tizimning fayl keshiga (Lucene unga tayanadi). Linux'da Docker bilan ishga tushirishda vm.max_map_count sozlamasini oshirish talab qilinadi. Kanon aynan resurs sababli sinamadi: image ~1 GB, heap 1–2 GB.
Bundan tashqari: klaster sog'lig'ini kuzatish (green/yellow/red), shard sonini rejalashtirish (keyin o'zgartirish qiyin), versiya yangilash, snapshot (zaxira). Bularning hammasi — operatsion ish. Kichik jamoa uchun bu ko'pincha hal qiluvchi: Elastic Cloud yoki Amazon OpenSearch Service kabi boshqariladigan xizmat — yoki soddaroq dvigatel.
9. Hujumchi nigohi
- Ochiq port. Internetda autentifikatsiyasiz Elasticsearch — eng ko'p uchraydigan ma'lumot sizishi sabablaridan biri: 9200-port ochiq qolgan klasterlardan millionlab yozuvlar o'g'irlangan. Himoya: 8-versiyadan beri xavfsizlik sukut bo'yicha yoqilgan — uni o'chirmang; portni faqat ichki tarmoqda oching.
- Foydalanuvchi bergan query DSL. Frontend tayyor JSON so'rov yuborsa va backend uni o'zgartirmasdan uzatsa — hujumchi
filterni olib tashlaydi yoki og'ir aggregation bilan klasterni yuklaydi. Himoya: so'rovni serversorovYasakabi funksiya bilan o'zi yig'adi. query_stringso'rovi. U Lucene sintaksisini tushunadi (egasi:8 OR *). Foydalanuvchi matniga ishlatsangiz — filtrni chetlab o'tish va xato sintaksis bilan 400. Himoya: foydalanuvchi matni uchunmatchyokisimple_query_string.- Chuqur sahifalash.
from: 100000— har shard 100 000+ hujjatni saralaydi. Elasticsearch sukut bo'yichafrom + sizeni 10 000 bilan cheklaydi (index.max_result_window). Chuqur o'tish uchunsearch_after— Pagination: offset, cursor, keyset darsidagi keyset g'oyasi.
10. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
term hech narsa topmaydi |
text maydon tahlil qilingan, term esa yo'q |
match yoki keyword maydon |
Aggregation text maydonda xato |
fielddata o'chiq |
keyword multi-field |
| Maydon turi noto'g'ri, tuzatib bo'lmaydi | dynamic mapping taxmini | yangi indeks + reindex |
| Yuklangan hujjat darhol topilmaydi | refresh hali bo'lmagan | kuting yoki testda refresh: true |
Result window is too large |
from + size > 10 000 |
search_after |
| Klient xatosi versiya haqida | klient va server katta versiyasi farqli | bir xil major versiya |
11. Mashqlar
Mashqlar kurs/mashqlar/29/54-elasticsearch/ da.
1-mashq (oson): bo'shliqlarni to'ldiring
- Tahlil qilinmaydigan, filtr va aggregation uchun satr turi —
- Ballga ta'sir qilmaydigan va keshlanadigan
boolbo'limi — fuzziness: "AUTO"4 harfli so'zga beradigan xato soni —- Indeksning alohida serverga joylashadigan bo'lagi —
- Elasticsearch'dan 2021-yilda ayrilgan Apache 2.0 loyiha —
Yechim
- keyword —
textesa analyzer'dan o'tadi. - filter — "mos yoki yo'q" shartlari uchun.
- 1 — 3–5 belgi — bitta xato.
- shard — nusxasi esa replica.
- OpenSearch — hozir OpenSearch Software Foundation qoshida.
2-mashq (o'rta): date_histogram oyma-oy
Darsdagi hujjatlar massivi uchun oylar(royxat) funksiyasini yozing: u { key: "2026-09", doc_count } ko'rinishidagi bucket'larni vaqt tartibida qaytarsin. Bo'sh oy bo'lsa (oraliqda hujjat yo'q oy), u ham doc_count: 0 bilan chiqsin — Elasticsearch'dagi min_doc_count: 0 kabi. Sinash uchun hujjatlarga 2026-12-05 sanali yana bittasini qo'shing.
Yechim
const hujjatlar = [
{ yaratilgan: "2026-09-14" },
{ yaratilgan: "2026-09-30" },
{ yaratilgan: "2026-10-02" },
{ yaratilgan: "2026-10-11" },
{ yaratilgan: "2026-10-27" },
{ yaratilgan: "2026-12-05" },
];
function oylar(royxat) {
const sanoq = new Map();
for (const h of royxat) {
const oy = h.yaratilgan.slice(0, 7);
sanoq.set(oy, (sanoq.get(oy) ?? 0) + 1);
}
const kalitlar = [...sanoq.keys()].sort();
let [y, m] = kalitlar[0].split("-").map(Number);
const oxirgi = kalitlar.at(-1);
const natija = [];
while (true) {
const key = `${y}-${String(m).padStart(2, "0")}`;
natija.push({ key, doc_count: sanoq.get(key) ?? 0 });
if (key === oxirgi) break;
m += 1;
if (m === 13) {
m = 1;
y += 1;
}
}
return natija;
}
console.log(oylar(hujjatlar));Konsolda:
[
{ key: '2026-09', doc_count: 2 },
{ key: '2026-10', doc_count: 3 },
{ key: '2026-11', doc_count: 0 },
{ key: '2026-12', doc_count: 1 }
]Kalit YYYY-MM satri bo'lgani uchun oddiy sort() vaqt tartibini beradi. Noyabr ro'yxatda 0 bilan bor — grafik chizganda bo'sh oy "yo'qolib qolmasligi" uchun shunday qilinadi. Oyni Date bilan emas, raqam bilan oshirdik — vaqt zonasi tuzog'idan qochish uchun (Backend'da sana va vaqt).
3-mashq (qiyin): must_not va should qo'shing
sorovYasa ni kengaytiring. Yangi parametrlar: istisno — vergul bilan ajratilgan ustuvorliklar (masalan "past,orta"), ular must_not ga terms so'rovi bo'lib tushsin (faqat ruxsat ro'yxatidagilar); muhim: "1" bo'lsa — should ga { term: { ustuvorlik: "yuqori" } } qo'shilsin (yuqori ustuvorlikdagilar ballni oshiradi, lekin shart emas). Bo'sh massivli bo'limlar natijaga kirmasin.
Yechim
const USTUVORLIK = new Set(["past", "orta", "yuqori"]);
function sorovYasa(egasiId, { q, istisno, muhim }) {
const bool = {
must: q
? [{ match: { matn: { query: q, fuzziness: "AUTO" } } }]
: [{ match_all: {} }],
filter: [{ term: { egasi: egasiId } }],
must_not: [],
should: [],
};
const chiqar = (istisno ?? "")
.split(",")
.map((x) => x.trim())
.filter((x) => USTUVORLIK.has(x));
if (chiqar.length > 0) {
bool.must_not.push({ terms: { ustuvorlik: chiqar } });
}
if (muhim === "1") {
bool.should.push({ term: { ustuvorlik: "yuqori" } });
}
for (const k of Object.keys(bool)) {
if (bool[k].length === 0) delete bool[k];
}
return { query: { bool } };
}
const a = sorovYasa(7, { istisno: "past, juda, orta" });
console.log(JSON.stringify(a));
const b = sorovYasa(7, { q: "hisobot", muhim: "1" });
console.log(JSON.stringify(b));Konsolda:
{"query":{"bool":{"must":[{"match_all":{}}],"filter":[{"term":{"egasi":7}}],"must_not":[{"terms":{"ustuvorlik":["past","orta"]}}]}}}
{"query":{"bool":{"must":[{"match":{"matn":{"query":"hisobot","fuzziness":"AUTO"}}}],"filter":[{"term":{"egasi":7}}],"should":[{"term":{"ustuvorlik":"yuqori"}}]}}}juda ruxsat ro'yxatida yo'q — jim tashlandi. Xato qaytarish ham to'g'ri yo'l bo'lardi: foydalanuvchi qiymatni noto'g'ri yozganini bilardi. Bu — API dizayn qarori. should must bor bo'lganda faqat ballni oshiradi; must va filter siz yolg'iz qolsa, hujjatga ko'ra kamida bittasi bajarilishi shart bo'ladi. Bizda filter doim bor — shuning uchun should ixtiyoriy bo'lib qoladi.
12. Loyiha qadami: sinalmagan, loyihaga kirmaydi
Bu darsda vazifalar-api ga kod qo'shilmaydi va kanonda Elasticsearch tajribasi yo'q. Sabab — resurs: shaxsiy vazifalar uchun gigabaytli JVM xizmatini ko'tarish o'rinsiz, Postgres FTS (27-qism) yetadi. Elasticsearch kerak bo'ladigan joy — loglar va katta katalog. Loglar mavzusi 34-qismda monitoring bilan qaytadi.
O'zingiz sinab ko'ring: kompyuteringizda kamida 4 GB bo'sh xotira bo'lsa, rasmiy hujjatdagi "local development" yo'riqnomasi bo'yicha Elasticsearch'ni ishga tushiring. _analyze API bilan darsdagi uz_matn analyzer'ini sinang va natijani tahlil() funksiyasi chiqishi bilan solishtiring.
13. Real ishda
- Loglar va kuzatuv — ELK/Elastic Stack (Elasticsearch + Logstash/Beats + Kibana) yoki OpenSearch + Dashboards: serverlar loglarini yig'ib, qidirish va grafik.
- Katta e-commerce katalogi — facet, sinonim, til analyzer'lari, shaxsiy saralash.
- Xavfsizlik (SIEM) — hodisalarni qidirish va korrelyatsiya.
- Boshqariladigan xizmatlar — Elastic Cloud, Amazon OpenSearch Service: klasterni o'zingiz boshqarmaysiz.
- Intervyuda: "
textvakeywordfarqi?", "mustvafilterfarqi?", "Shard va replica nima?", "Nega OpenSearch paydo bo'ldi?"
Xulosa
- Mapping — indeks sxemasi:
textqidiruv uchun tahlil qilinadi,keywordaniq qiymat, filtr va aggregation uchun. - Analyzer = character filter + tokenizer + token filter'lar; o'zbekcha uchun o'zingiz yig'asiz.
bool: so'z —must, ballsiz shartlar —filter; so'rovni server JSON qilib o'zi yig'adi.fuzziness: "AUTO"— so'z uzunligiga qarab 0, 1 yoki 2 xato.- Aggregation — qidiruv bilan birga hisob; shard'li indeksda
termssanog'i taxminiy bo'lishi mumkin. - Elasticsearch va OpenSearch — kuchli, lekin og'ir; litsenziya va resursni hisobga olib tanlanadi. Bu dars sinalmagan — hujjat bo'yicha.
Keyingi dars: Backend'da ko'p tillilik (i18n) — foydalanuvchi tilini aniqlash, ko'plik shakllari, ICU xabarlari, lotin-kirill transliteratsiyasi va bazada ko'p tilli kontent.
Manbalar
- Elasticsearch — mapping va maydon turlari: https://www.elastic.co/docs/manage-data/data-store/mapping
- Elasticsearch — analyzer anatomiyasi: https://www.elastic.co/docs/manage-data/data-store/text-analysis/anatomy-of-an-analyzer
- Elasticsearch — query DSL (
bool,match,fuzziness): https://www.elastic.co/docs/explore-analyze/query-filter/languages/querydsl - Elasticsearch — aggregation'lar: https://www.elastic.co/docs/explore-analyze/query-filter/aggregations
@elastic/elasticsearchklienti: https://www.elastic.co/docs/reference/elasticsearch/clients/javascript- Elastic — "Elasticsearch is Open Source. Again!" (AGPL, 2024-08-29): https://www.elastic.co/blog/elasticsearch-is-open-source-again
- OpenSearch: https://opensearch.org/ va https://docs.opensearch.org/
- Kanon (IlmHamroh, 2026-10-27): Elasticsearch va OpenSearch SINALMAGAN (resurs). Darsdagi Elasticsearch kodi — hujjat bo'yicha (2026-10). JavaScript bloklari va mashq yechimlari — biz ishga tushirdik (2026-10-28, Node 24.21.0).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!