30 վայրկյանում
Elasticsearch-ը բաշխված որոնման շարժիչ է՝ կառուցված Apache Lucene-ի վրա։ Այն analyzer-ներով տեքստը վերածում է term-երի և պահում inverted index-ում, այնպես որ կարող է միլիոնավոր գրառումների մեջ միլիվայրկյանների ընթացքում գտնել և դասակարգել համապատասխան փաստաթղթերը։ Այն նաև կատարում է ագրեգացիաներ, աշխատում է լոգերի հետ, իսկ վերջերս՝ vector և hybrid որոնում։ Ընթացիկ մեծ գիծը 9.x-ն է․ OpenSearch-ը նրա open-source fork-ն է։
Իմ ամենօրյա stack-ում չէ․ գիտեմ հիմնական գաղափարները և մանրամասները կսովորեմ, երբ նախագիծը դա պահանջի։
Ինչու է սա կարևոր
- Օգտատերերը սպասում են որոնում, որը ներում է տառասխալները, հասկանում է բառաձևերը և լավագույն արդյունքը դնում առաջինը։ SQL LIKE հարցումը մասշտաբով դա չի կարող, իսկ relevance scoring-ով inverted index-ը կարող է։
- Այն բազմաթիվ լոգերի և observability stack-երի (Elastic Stack) հիմքն է, որտեղ հսկայական ծավալների արագ ֆիլտրումն ու ագրեգացիան ավելի կարևոր են, քան տրանզակցիաները։
- Թիմերն այն ընտրում են, երբ որոնման վրա լիարժեք վերահսկողություն է պետք՝ յուրաքանչյուր լեզվի համար custom analyzer-ներ, հոմանիշներ, boosting կանոններ և faceted նավիգացիա՝ սեփական սերվերի վրա կամ կառավարվող։
- Այն հակադրվում է Algolia-ի նման hosted որոնման ծառայություններին․ ավելի շատ կարգավորում և operations աշխատանք, բայց ավելի շատ ճկունություն, առանց յուրաքանչյուր որոնման համար վճարի և տվյալները ձեր ենթակառուցվածքում պահելու հնարավորությամբ։
Ինչպես է աշխատում
01Գաղափարը՝ inverted index
Գրքի ցուցիչը թվարկում է բառերը և այն էջերը, որտեղ դրանք հանդիպում են։ Inverted index-ը նույնն է անում փաստաթղթերի համար․ յուրաքանչյուր term-ի համար պահում է այն պարունակող փաստաթղթերի ID-ների ցուցակը՝ գումարած դիրքերն ու հաճախականությունները։ «red running shoes» որոնելու համար Elasticsearch-ը նայում է երեք կարճ ցուցակ և հատում կամ միավորում դրանք՝ յուրաքանչյուր փաստաթուղթ կարդալու փոխարեն։ Relevance-ը լռելյայն հաշվվում է BM25-ով․ term-ն ավելի շատ է կշռում, եթե այն հազվադեպ է ամբողջ ինդեքսում և հաճախ է հանդիպում փաստաթղթում, և ավելի քիչ՝ շատ երկար դաշտերում։ Elasticsearch-ը near real-time է․ նոր փաստաթղթերը որոնելի են դառնում refresh-ից հետո, որը լռելյայն տեղի է ունենում ամեն վայրկյան։
- Index՝ փաստաթղթերի տրամաբանական հավաքածու մեկ mapping-ով, աղյուսակի նման։
- Document՝ JSON օբյեկտ, միավորը, որը ինդեքսավորում և որոնում եք։
- Term՝ analyzer-ի կողմից ստեղծված նորմալացված token, օրինակ՝ «running»-ը դառնում է «run»։
02Mapping-ներ և analyzer-ներ
Mapping-ը սահմանում է յուրաքանչյուր դաշտի տիպը։ Ամենակարևոր տարբերությունը text-ի և keyword-ի միջև է։ Text դաշտը վերլուծվում է՝ բաժանվում է token-ների, փոքրատառվում, գուցե stemming է անցնում, այնպես որ այն լավ է full-text որոնման համար, բայց ոչ դասավորման կամ ճշգրիտ ֆիլտրերի համար։ Keyword դաշտը պահվում է որպես մեկ ճշգրիտ արժեք՝ լավ ֆիլտրերի, դասավորման և ագրեգացիաների համար (brand, status, SKU)։ Հաճախ դաշտը mapping եք անում երկու ձևով՝ sub-field-ով։ Analyzer-ը pipeline է՝ character filter-ներ, tokenizer և token filter-ներ (lowercase, stop words, stemming, հոմանիշներ)։ Յուրաքանչյուր դաշտի համար ընտրեք լեզվական analyzer-ներ (english, german, russian…)։ Սահմանեք mapping-ները բացահայտ․ dynamic mapping-ը գուշակում է տիպերը և հաճախ սխալ է գուշակում։
PUT /products
{
"settings": { "number_of_shards": 1, "number_of_replicas": 1 },
"mappings": {
"dynamic": "strict",
"properties": {
"name": { "type": "text", "analyzer": "english",
"fields": { "raw": { "type": "keyword" } } },
"brand": { "type": "keyword" },
"price": { "type": "scaled_float", "scaling_factor": 100 },
"in_stock": { "type": "boolean" },
"created_at": { "type": "date" }
}
}
}
03Հարցումներ՝ query context և filter context
Որոնումն օգտագործում է Query DSL՝ JSON լեզու։ Bool query-ն համադրում է clause-ներ․ must-ը և should-ը ներդրում են relevance score-ում, filter-ը և must_not-ը միայն ներառում կամ բացառում են։ Filter-ները cache են արվում և score չեն հաշվում, այնպես որ յուրաքանչյուր այո/ոչ պայման (առկա է պահեստում, brand, գնի միջակայք) դրեք filter-ում, իսկ must-ը պահեք այն բանի համար, ինչ օգտատերը մուտքագրել է։ multi_match-ը որոնում է մի քանի դաշտում և թույլ է տալիս boost անել դրանցից մեկը, օրինակ՝ name-ը description-ից բարձր։ fuzziness: "AUTO"-ն հանդուրժում է տառասխալները։ Ագրեգացիաներն աշխատում են նույն request-ում՝ facet-ներ կառուցելու համար, օրինակ՝ քանակներ ըստ brand-ի, այնպես որ մեկ կանչը վերադարձնում է և՛ արդյունքները, և՛ sidebar-ի ֆիլտրերը։
GET /products/_search
{
"query": {
"bool": {
"must": { "multi_match": { "query": "red runing shoes",
"fields": ["name^3", "description"], "fuzziness": "AUTO" } },
"filter": [
{ "term": { "in_stock": true } },
{ "range": { "price": { "lte": 120 } } }
]
}
},
"aggs": { "brands": { "terms": { "field": "brand", "size": 10 } } },
"size": 20
}
04Կլաստեր, shard-եր և replica-ներ
Ինդեքսը բաժանվում է primary shard-երի, որոնցից յուրաքանչյուրն ինքնուրույն Lucene ինդեքս է, և յուրաքանչյուր primary կարող է այլ node-երում replica պատճեններ ունենալ։ Shard-երն այն միջոցն են, որով Elasticsearch-ը բաշխում է տվյալները և զուգահեռացնում հարցումները․ replica-ները ապահովում են failover և լրացուցիչ ընթերցման հզորություն։ Հարցումը տարածվում է յուրաքանչյուր shard-ի մեկ պատճենի վրա, յուրաքանչյուրը վերադարձնում է իր top hit-երը, և coordinating node-ը միավորում է դրանք։ Primary shard-երի քանակը ֆիքսվում է ինդեքսի ստեղծման ժամանակ (փոխելու համար պետք է split, shrink կամ reindex), այնպես որ չափը որոշեք սպասվող տվյալներից․ Elastic-ի ուղեցույցը մոտավորապես 10–50 GB է յուրաքանչյուր shard-ի համար և ոչ ավելի, քան մոտ 200 միլիոն փաստաթուղթ։ Չափազանց շատ փոքր shard-երը հիշողություն են վատնում, իսկ մի քանի հսկայականները դանդաղ են վերականգնվում։
- Կլաստերի health green՝ բոլոր shard-երը նշանակված են․ yellow՝ replica-ներ են բացակայում․ red՝ primary է բացակայում։
- Node-երի դերեր՝ master-eligible, data (hot, warm, cold, frozen), ingest, coordinating, ml։
- Պրոդակշն կլաստերի համար օգտագործեք երեք master-eligible node՝ split որոշումներից խուսափելու համար։
05Ինդեքսավորում հավելվածից՝ անվտանգ
Ձեր հիմնական բազան մնում է ճշմարտության աղբյուրը․ Elasticsearch-ը ածանցյալ, որոնելի պատճեն է։ Ինդեքսավորեք փաստաթղթերը batch-երով _bulk API-ով, ոչ թե մեկ request յուրաքանչյուր փաստաթղթի համար։ Օգտագործեք ձեր բազայի ID-ն որպես Elasticsearch-ի _id, որպեսզի վերաինդեքսավորումը idempotent լինի։ Փոփոխությունների համար կամ յուրաքանչյուր գրառումից հետո հերթագրեք ինդեքսավորման job (outbox-ը կամ հերթը դա հուսալի են պահում), կամ օգտագործեք change data capture։ Միշտ կարդացեք և գրեք alias-ի միջոցով, ոչ թե իրական ինդեքսի անունով․ երբ mapping-ը պետք է փոխվի, կառուցեք նոր ինդեքս, reindex արեք դրա մեջ և alias-ը ատոմար փոխարկեք։ Անվտանգությունը լռելյայն միացված է 8.0-ից (TLS և authentication), այնպես որ օգտագործեք API key՝ միայն այն արտոնություններով, որոնք հավելվածին պետք են։
POST /_bulk
{ "index": { "_index": "products", "_id": "1001" } }
{ "name": "Trail running shoe", "brand": "acme", "price": 89.9, "in_stock": true }
{ "index": { "_index": "products", "_id": "1002" } }
{ "name": "Road running shoe", "brand": "acme", "price": 99.0, "in_stock": false }
POST /_aliases
{ "actions": [
{ "remove": { "index": "products_v1", "alias": "products_live" } },
{ "add": { "index": "products_v2", "alias": "products_live" } }
] }
06Լիցենզիաներ, OpenSearch և կառավարվող տարբերակներ
2021-ին Elastic-ը Apache 2.0-ից անցավ SSPL-ի և Elastic License-ի, և AWS-ը վերջին բաց տարբերակը fork արեց OpenSearch-ի, որն այժմ կառավարվում է OpenSearch Software Foundation-ի կողմից Linux Foundation-ի ներքո։ 2024-ին Elastic-ը սկզբնական կոդի համար ավելացրեց AGPLv3-ը որպես լիցենզիայի տարբերակ։ Երկու նախագծերն ունեն ընդհանուր արմատներ և Query DSL-ի մեծ մասը, բայց տարբերվել են ֆունկցիաներով, plugin-ներով և client գրադարաններով, այնպես որ ընտրեք մեկը և օգտագործեք նրա սեփական client-ը։ Հոսթինգի տարբերակներն են Elastic Cloud-ը (ներառյալ serverless առաջարկը), Amazon OpenSearch Service-ը կամ սեփական կլաստերներ VM-ների կամ Kubernetes-ի վրա (Elasticsearch-ի համար՝ ECK operator-ով)։
Օգտագործեք, երբ
- Ապրանքների, փաստաթղթերի կամ կայքի որոնում, որին պետք են relevance դասակարգում, տառասխալների հանդուրժում, հոմանիշներ և facet-ներ։
- Լոգերի, մետրիկների և իրադարձությունների անալիտիկա, որտեղ մեծ ծավալներ եք ֆիլտրում և ագրեգացնում near real time-ում։
- Autocomplete և search-as-you-type մեծ կատալոգների վրա։
- Hybrid որոնում, որը մեկ շարժիչում համադրում է keyword relevance-ը vector similarity-ի հետ։
Մի՛ օգտագործեք, երբ
- Որպես տրանզակցիոն տվյալների հիմնական բազա․ այն չունի բազմափաստաթղթային տրանզակցիաներ և eventually consistent է։
- Փոքր կատալոգի համար, որտեղ PostgreSQL full-text search-ը կամ hosted ծառայությունը ծածկում է կարիքը՝ շատ ավելի քիչ operations աշխատանքով։
- Ծանր ռելյացիոն join-եր կամ խիստ consistency պահանջներ։
Այլընտրանքներ
- OpenSearch
Apache 2.0 fork-ը․ նման API, ուժեղ ինտեգրացիա AWS-ի հետ, սեփական plugin էկոհամակարգ։
- Algolia
Hosted search-as-a-service՝ շատ արագ կարգավորմամբ և տառասխալների հիանալի հանդուրժմամբ․ գինն աճում է գրառումների և request-ների հետ։
- Meilisearch / Typesense
Թեթև open-source որոնման շարժիչներ, որոնք հեշտ է աշխատեցնել, հարմար են փոքր և միջին dataset-երի համար։
- PostgreSQL full-text search
tsvector և GIN ինդեքսներ ձեր բազայի ներսում․ բավականաչափ լավ է շատ հավելվածների համար՝ առանց երկրորդ համակարգի։
Լավագույն պրակտիկաներ
- Սահմանեք բացահայտ mapping-ներ (dynamic: strict կամ false) և string-երը գիտակցաբար mapping արեք որպես text, keyword կամ երկուսը։
- Այո/ոչ պայմանները դրեք filter context-ում, որպեսզի դրանք cache արվեն և չազդեն scoring-ի վրա։
- Միշտ դիմեք ինդեքսներին alias-ների միջոցով, որպեսզի reindex-ը և mapping-ի փոփոխությունները downtime չպահանջեն։
- Shard-երի չափը պահեք մոտավորապես 10–50 GB, փոքր ինդեքսների համար օգտագործեք մեկ primary shard և խուսափեք հազարավոր փոքր shard-երից։
- Ինդեքսավորեք _bulk API-ով և ձեր բազայի ID-ն օգտագործեք որպես _id՝ idempotent թարմացումների համար։
- Լոգերի համար օգտագործեք data stream-ներ և index lifecycle management (ILM), որպեսզի հին տվյալները տեղափոխվեն ավելի էժան tier-եր և ջնջվեն ըստ ժամանակացույցի։
- Անվտանգությունը պահեք միացված, օգտագործեք սահմանափակ API key-եր և կանոնավոր snapshot-ներ արեք object storage-ում։
Տարածված սխալներ
- Ապավինել dynamic mapping-ին, որը յուրաքանչյուր string-ի համար ստեղծում է text գումարած keyword և թվերն ու ամսաթվերը անհամապատասխան է mapping անում։
- Հազարավոր էջերի համար from-ով և size-ով խորը pagination օգտագործել՝ point in time-ով search_after-ի փոխարեն։
- Elasticsearch-ը որպես ճշմարտության աղբյուր օգտագործել և կորցնել տվյալներ, որոնք այլ տեղ գոյություն չունեն։
- Ամեն օր յուրաքանչյուր հաճախորդի համար նոր ինդեքս ստեղծել և հայտնվել տասնյակ հազարավոր shard-երով։
- Term query աշխատեցնել text դաշտի վրա, ինչը ձախողվում է, քանի որ պահված term-երը վերլուծված և փոքրատառված են։
Խորը վերլուծություն
07Segment-ներ, refresh, flush և merge-եր
Յուրաքանչյուր shard-ի ներսում Lucene-ը տվյալները գրում է անփոփոխ segment-ներում։ Նոր փաստաթղթերը գնում են հիշողության buffer և translog (write-ahead log)։ Refresh-ը (լռելյայն ամեն 1 վայրկյան, միայն վերջերս որոնված ինդեքսներում) buffer-ը վերածում է նոր որոնելի segment-ի․ flush-ը segment-ները commit է անում սկավառակին և կրճատում translog-ը։ Քանի որ segment-ներն անփոփոխ են, update-ներն իրականում delete գումարած insert են, և ջնջված փաստաթղթերը հեռացվում են միայն այն ժամանակ, երբ ֆոնային merge-երը փոքր segment-ները միավորում են ավելի մեծերի։ Bulk բեռնումների համար refresh_interval-ը դրեք -1, replica-ները՝ 0, բեռնեք, ապա վերականգնեք երկուսն էլ․ դա կարող է բազմապատկել ինդեքսավորման արագությունը։ Խուսափեք նույն ID-ների վրա մեկական փաստաթղթի հաճախակի update-ներից, որոնք ստեղծում են բազմաթիվ փոքր segment-ներ և ջնջված փաստաթղթեր։
PUT /products_v2/_settings
{ "index": { "refresh_interval": "-1", "number_of_replicas": 0 } }
// ...run the bulk load, then:
PUT /products_v2/_settings
{ "index": { "refresh_interval": "1s", "number_of_replicas": 1 } }
POST /products_v2/_refresh
08Vector, semantic և hybrid որոնում
Elasticsearch 8-ը և 9-ը աջակցում են dense_vector դաշտեր՝ մոտավոր kNN որոնմամբ HNSW գրաֆների միջոցով, quantization-ով (int8, int4 և BBQ՝ binary quantization)՝ հիշողությունը կրճատելու համար։ semantic_text դաշտի տիպը գնում է ավելի հեռու․ կցում եք inference endpoint, և Elasticsearch-ը ինդեքսավորման ժամանակ տեքստը բաժանում է chunk-երի և ստեղծում embedding-ներ։ Retriever-ները թույլ են տալիս ստանդարտ BM25 հարցումը համադրել kNN հարցման հետ reciprocal rank fusion-ով (RRF), որը երկու դասակարգված ցուցակները միավորում է ըստ դիրքի՝ raw score-ի փոխարեն։ Hybrid որոնումը սովորաբար գերազանցում է յուրաքանչյուր մեթոդին առանձին․ keyword-երը բռնում են ճշգրիտ SKU-ներն ու անունները, vector-ները՝ իմաստը։ Չափեք պիտակավորված հարցումների հավաքածուով՝ առաջ և հետո։
GET /products/_search
{
"retriever": { "rrf": { "retrievers": [
{ "standard": { "query": { "match": { "name": "waterproof hiking boots" } } } },
{ "knn": { "field": "name_vector", "k": 20, "num_candidates": 100,
"query_vector_builder": { "text_embedding": {
"model_id": "my-embedding-endpoint", "model_text": "waterproof hiking boots" } } } }
] } }
}
09Խորը pagination և հետևողական scrolling
from + size pagination-ը ստիպում է յուրաքանչյուր shard-ին հավաքել from + size hit-եր, իսկ coordinator-ին՝ դասավորել դրանք բոլորը, այնպես որ 500-րդ էջը շատ թանկ է․ հենց այդ պատճառով լռելյայն սահմանը (index.max_result_window) 10,000 արդյունք է։ Օգտատիրոջ համար infinite scrolling-ի կամ export-ների համար օգտագործեք search_after՝ sort-ով, որն ավարտվում է եզակի tiebreaker-ով, point in time-ի (PIT) հետ համատեղ, որպեսզի տեսքը չտեղաշարժվի նոր փաստաթղթերի ժամանման ժամանակ։ Ավելի հին scroll API-ն դեռ հասանելի է, բայց այլևս խորհուրդ չի տրվում խորը pagination-ի համար։ Շատ մեծ արդյունքների հավաքածուների export-ի համար դիտարկեք զուգահեռ sliced PIT որոնումներ։
10Կլաստերի շահագործում՝ հիշողություն, tier-եր և snapshot-ներ
JVM heap-ին տվեք RAM-ի ոչ ավելի, քան մոտ կեսը և մնացեք compressed-pointer շեմից ցածր (մոտ 30 GB)․ մնացածն օգտագործվում է OS file cache-ի կողմից, որին Lucene-ը մեծապես ապավինում է։ Վերջին տարբերակները heap-ի չափը որոշում են ավտոմատ, ինչը սովորաբար ճիշտ է։ Ժամանակային տվյալների համար օգտագործեք hot, warm, cold և frozen data tier-եր ILM-ով, որպեսզի հին ինդեքսները տեղափոխվեն ավելի էժան պահոց և ի վերջո ջնջվեն։ Կանոնավոր snapshot արեք object storage-ում (S3, GCS, Azure) snapshot lifecycle management-ով․ snapshot-ները incremental են և ձեր իրական backup-ն են, քանի որ replica-ները չեն պաշտպանում ինդեքսի ջնջումից։ Upgrade արեք rolling restart-ներով մեկ major-ի ներսում և major upgrade-ներից առաջ ստուգեք deprecation API-ն։
Իրական իրավիճակներ
Որոնումը ոչինչ չի վերադարձնում ճշգրիտ SKU-ի համար
Խնդիր
Օգտատերերը որոնման մեջ տեղադրում են «AB-1234-XL»-ի նման SKU և արդյունք չեն ստանում, թեև ապրանքը գոյություն ունի։ SKU-ն mapping է արված որպես text դաշտ՝ standard analyzer-ով։
Ինչպես լուծել
Standard analyzer-ը SKU-ն բաժանում է գծիկներով և փոքրատառում, այնպես որ ճշգրիտ string-ը երբեք որպես մեկ term գոյություն չունի։ Ավելացրեք keyword sub-field (sku.raw)՝ lowercase normalizer-ով, reindex արեք alias-ի հետևում, և որոնման request-ում ավելացրեք should clause՝ sku.raw-ի վրա term query-ով՝ բարձր boost-ով, սովորական multi_match-ի կողքին։ Ըստ ցանկության հավելվածում regex-ով հայտնաբերեք SKU-ի նման մուտքը և նախ կատարեք ճշգրիտ lookup։ Relevance թեստային հավաքածուին ավելացրեք regression թեստ իրական SKU-ներով, որպեսզի խնդիրը չվերադառնա mapping-ի ապագա փոփոխություններից հետո։
Կլաստերը կարմրում է node-ի ընկնելուց հետո
Խնդիր
Երեք node-անոց կլաստերում ինդեքսներն ունեին զրո replica՝ սկավառակ խնայելու համար։ Մի node գիշերը ձախողվեց, և մի քանի ինդեքս այժմ red են, պրոդակշնում որոնման սխալներով։
Ինչպես լուծել
Red-ը նշանակում է, որ primary shard-ը հասանելի պատճեն չունի, այնպես որ նրա տվյալներն offline են, մինչև այդ node-ը վերադառնա կամ վերականգնեք։ Վերադարձրեք node-ը, եթե սկավառակն անվնաս է․ հակառակ դեպքում վերականգնեք ազդված ինդեքսները վերջին snapshot-ից կամ վերակառուցեք դրանք աղբյուր բազայից, եթե Elasticsearch-ը ածանցյալ ինդեքս է։ Օգտագործեք cluster allocation explain API-ն՝ տեսնելու, թե ինչու են shard-երը չնշանակված։ Դրանից հետո բոլոր պրոդակշն ինդեքսներում դրեք առնվազն մեկ replica, ավելացրեք սկավառակային տարողություն կամ ILM ջնջում՝ դրա համար վճարելու համար, կարգավորեք snapshot lifecycle management և ալերտ դրեք կլաստերի yellow health-ի վրա, ոչ միայն red-ի։
Դանդաղ faceted որոնում մեծ կատալոգում
Խնդիր
Հինգ facet-ով որոնումները տասը միլիոն ապրանքի ինդեքսում տևում են 1.5 վայրկյան։ Profiling-ը ցույց է տալիս, որ ժամանակի մեծ մասը ծախսվում է ագրեգացիաների և scoring-ի վրա։
Ինչպես լուծել
Բոլոր facet-ների ընտրությունները տեղափոխեք filter context, որպեսզի դրանք cache արվեն և score չստանան։ Terms ագրեգացիաների համար օգտագործեք keyword դաշտեր doc_values-ով և դրանց size-ը պահեք փոքր։ Այն facet-ների համար, որոնք պետք է քանակներ ցույց տան այլ ընտրությունների միջով, օգտագործեք post_filter, որպեսզի ագրեգացիաներն աշխատեն ավելի լայն հավաքածուի վրա միայն մեկ անգամ։ Ստուգեք shard-ի չափը․ 2 GB-անոց 30 shard ունեցող ինդեքսն անտեղի է տարածվում, այնպես որ shrink արեք ավելի քիչ shard-երի։ Միացրեք request cache-ը կրկնվող միայն ագրեգացիոն request-ների համար։ Օգտագործեք profile API-ն՝ յուրաքանչյուր փոփոխությունը հաստատելու համար, և համեմատեք p95 latency-ն առաջ և հետո՝ իրական հարցումների replay-ով։
Արագ ուղեցույց
- Կլաստերի health
GET /_cluster/health?pretty- Ինդեքսների ցուցակ՝ չափերով
GET /_cat/indices?v&s=store.size:desc- Ստուգել, թե ինչպես է տեքստը վերլուծվում
POST /products/_analyze { "field": "name", "text": "Running Shoes" }- Բացատրել, թե ինչու է shard-ը չնշանակված
GET /_cluster/allocation/explain- Reindex նոր ինդեքսի մեջ
POST /_reindex { "source": { "index": "products_v1" }, "dest": { "index": "products_v2" } }- Alias-ի ատոմար փոխարկում
POST /_aliases { "actions": [ { "remove": {...} }, { "add": {...} } ] }- Դանդաղ հարցման profile
GET /products/_search { "profile": true, "query": { ... } }- Բացել point in time
POST /products/_pit?keep_alive=1m- Ստեղծել API key
POST /_security/api_key { "name": "app-search", "role_descriptors": { ... } }
Հարցեր և պատասխաններ
Q1Ո՞րն է տարբերությունը text և keyword դաշտերի միջև։
Text դաշտը վերլուծվում է ինդեքսավորման ժամանակ․ analyzer-ը այն բաժանում է token-ների, փոքրատառում և կարող է հեռացնել stop word-երը կամ stemming անել, այնպես որ «Running Shoes»-ը դառնում է run և shoe term-երը։ Դա այն է, ինչ ուզում եք full-text որոնման համար։ Keyword դաշտը պահվում է որպես մեկ ճշգրիտ արժեք, ինչը պետք է ֆիլտրերի, դասավորման և ագրեգացիաների համար, օրինակ՝ brand-ի կամ status-ի։ Text դաշտի վրա term query-ն սովորաբար ձախողվում է, քանի որ այն փնտրում է ճշգրիտ չվերլուծված արժեքը։ Տարածված պատերնը text դաշտն է keyword sub-field-ով, որպեսզի կարողանաք և՛ որոնել, և՛ դասավորել կամ facet անել։
Q2Ինչպե՞ս է Elasticsearch-ը դասակարգում արդյունքները։
Լռելյայն այն օգտագործում է BM25՝ հավանականային relevance մոդել։ Հարցման յուրաքանչյուր term-ի համար այն հաշվի է առնում term-ի հաճախականությունը փաստաթղթում (ավելին՝ ավելի լավ, նվազող օգուտով), inverse document frequency-ն (հազվադեպ term-երն ավելի շատ են կշռում) և դաշտի երկարությունը (կարճ վերնագրում համընկնումը գերազանցում է երկար մարմնում համընկնմանը)։ must և should clause-ների score-երը համադրվում են։ Relevance-ը ձևավորում եք field boost-երով, function_score-ով կամ rank_feature-ով՝ բիզնես ազդանշանների համար, ինչպիսին հանրաճանաչությունն է, և հոմանիշներով։ Filter clause-ները չեն ազդում score-ի վրա։ Սեմանտիկ relevance-ի համար կարող եք ավելացնել vector որոնում և երկու ցուցակները համադրել reciprocal rank fusion-ով։
Q3Քանի՞ shard պետք է ունենա ինդեքսը։
Ավելի քիչ, քան մարդկանց մեծ մասը կարծում է։ Յուրաքանչյուր shard Lucene ինդեքս է՝ իր հիշողության և ֆայլերի overhead-ով, և յուրաքանչյուր որոնում դիպչում է յուրաքանչյուր shard-ի մեկ պատճենին։ Elastic-ի ուղեցույցն է ձգտել մոտավորապես 10-ից 50 GB shard-երի և յուրաքանչյուր node-ի վրա shard-երի ընդհանուր քանակը չափավոր պահել։ Մի քանի գիգաբայթանոց կատալոգը պետք է ունենա մեկ primary shard և մեկ replica։ Աճող լոգային տվյալների համար օգտագործեք data stream-ներ՝ rollover-ով ըստ չափի կամ տարիքի, որպեսզի յուրաքանչյուր backing index ավտոմատ ստանա ողջամիտ չափ։ Եթե սխալվեք, կարող եք ինդեքսը split կամ shrink անել կամ reindex անել alias-ի հետևում։
Q4Ինչպե՞ս փոխել mapping-ը առանց downtime-ի։
Գոյություն ունեցող դաշտի տիպը տեղում փոխել չեք կարող, քանի որ տվյալներն արդեն ինդեքսավորված են այդ ձևով։ Անվտանգ գործընթացն է՝ ստեղծել նոր ինդեքս (products_v2) նոր mapping-ով, reindex անել հին ինդեքսից կամ աղբյուր բազայից, փոխարկման ընթացքում երկուսը սինքրոն պահել (օրինակ՝ գրելով երկուսում էլ կամ վերարտադրելով փոփոխությունները), ապա մեկ _aliases request-ով alias-ը ատոմար տեղափոխել v1-ից v2։ Հավելվածները միշտ խոսում են alias-ի հետ, այնպես որ երբեք չեն նկատում։ Հին ինդեքսը պահեք կարճ rollback պատուհանի համար, ապա ջնջեք։ Նոր դաշտեր ավելացնելը թույլատրվում է առանց reindex-ի։
Q5Elasticsearch-ը տվյալների բազա է՞։
Այն տվյալները պահում է հուսալի և հնարավոր է հարցումներ անել, բայց ես այն չէի օգտագործի որպես բիզնես գրառումների հիմնական բազա։ Այն չունի բազմափաստաթղթային տրանզակցիաներ, գրառումները տեսանելի են միայն refresh-ից հետո, և որոշ գործողություններ, ինչպես mapping-ի փոփոխությունները, պահանջում են reindex ինչ-որ տեղից։ Կլաստերի խնդիրները նաև կարող են վերականգնումն ավելի դժվար դարձնել, քան ռելյացիոն backup-ի վերականգնումը։ Հուսալի պատերնն է ճշմարտության աղբյուրը պահել PostgreSQL-ում, MySQL-ում կամ MongoDB-ում և Elasticsearch-ը դիտարկել որպես ածանցյալ ինդեքս, որը կարող եք ցանկացած պահի վերակառուցել։ Լոգերի և observability-ի համար, որտեղ տվյալները միայն ավելացվում են, ընդունելի է այն օգտագործել որպես հիմնական պահոց՝ snapshot-ներով։
Q6Elasticsearch, թե՞ hosted ծառայություն, ինչպիսին Algolia-ն է։
Algolia-ն մեկ օրվա ընթացքում տալիս է տառասխալների գերազանց հանդուրժում, ակնթարթային արդյունքներ և կոկիկ dashboard, և դուք երբեք սերվերներ չեք աշխատեցնում։ Փոխզիջումներն են գինը, որն աճում է գրառումների և որոնման request-ների հետ, ranking-ի ներքին մասերի վրա ավելի քիչ վերահսկողությունը և տվյալների գտնվելը երրորդ կողմի մոտ։ Elasticsearch-ը, սեփական սերվերի վրա կամ Elastic Cloud-ում, պահանջում է ավելի շատ կարգավորում և relevance աշխատանք, բայց առաջարկում է custom analyzer-ներ, ագրեգացիաներ անալիտիկայի համար, vector որոնում և կանխատեսելի ենթակառուցվածքային ծախսեր մասշտաբում։ Փոքր կամ միջին խանութի և փոքր թիմի համար hosted որոնումը հաճախ պրագմատիկ ընտրություն է․ մեծ կատալոգների, բարդ facet-ների կամ լոգերի համար հաղթում են Elasticsearch-ը կամ OpenSearch-ը։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս կպահեիք Elasticsearch-ը սինքրոն ռելյացիոն բազայի հետ մասշտաբում։
Request path-ում կրկնակի գրառումները փխրուն են․ բազայի commit-ը կարող է հաջողվել, իսկ ինդեքսի կանչը՝ ձախողվել։ Ես նախընտրում եմ ասինխրոն pipeline։ Կամ հավելվածը նույն տրանզակցիայում գրում է outbox տող, և worker-ը ինդեքսավորում է outbox-ից, կամ change data capture գործիքը, ինչպիսին Debezium-ն է, կարդում է binlog-ը կամ WAL-ը և հրապարակում փոփոխություններ, որոնք indexer-ը սպառում է։ Indexer-ն օգտագործում է բազայի ID-ն որպես _id, external versioning (version_type external՝ updated_at-ով կամ հաջորդական համարով), որպեսզի սխալ հերթականությամբ եկած իրադարձությունները չկարողանան վերագրել ավելի նոր տվյալները, և _bulk՝ throughput-ի համար։ Ես մոնիտորինգ եմ անում lag-ը և alias-ի հետևում պահում եմ ամբողջական reindex job՝ disaster recovery-ի և mapping-ի փոփոխությունների համար։ Փոխզիջումը վայրկյանների eventual consistency-ն է, որը որոնումը սովորաբար հանդուրժում է։
S2Ինչպե՞ս եք չափում և բարելավում որոնման relevance-ը։
Relevance-ը պրոդուկտային մետրիկ է, այնպես որ վերաբերվեք դրան որպես այդպիսին։ Կազմեք judgement list՝ լոգերից մի քանի հարյուր իրական հարցում այն փաստաթղթերով, որոնք պետք է բարձր դասակարգվեն, գնահատված դոմենը իմացող մարդկանց կողմից։ Օգտագործեք rank evaluation API-ն՝ ընթացիկ կոնֆիգուրացիայի համար nDCG-ի կամ MRR-ի նման մետրիկներ հաշվելու համար։ Ապա միանգամից մեկ բան փոխեք՝ analyzer-ներ, հոմանիշներ, field boost-եր, function_score հանրաճանաչությամբ կամ մարժայով, կամ vector retriever-ի ավելացում RRF-ով։ Կրկին աշխատեցրեք գնահատումը և պահեք այն փոփոխությունները, որոնք բարելավում են այն՝ առանց հայտնի հարցումները կոտրելու։ Online-ում հետևեք click-through-ին, zero-result rate-ին և search exit-երին, և մեծ փոփոխությունները A/B թեստավորեք։ Առանց այս ցիկլի relevance-ի կարգավորումը դառնում է կարծիք, և յուրաքանչյուր ուղղում կոտրում է մեկ այլ հարցում։
S3Elasticsearch, թե՞ OpenSearch նոր նախագծի համար 2026-ին։
Երկուսն էլ հասուն Lucene-ի վրա հիմնված շարժիչներ են նման հիմնական API-ներով, այնպես որ որոշումը հիմնականում վերաբերում է էկոհամակարգին, լիցենզիային և հոսթինգին։ Elasticsearch-ն ավելի արագ է առաջ գնում այնպիսի ֆունկցիաներով, ինչպիսիք են semantic_text-ը, retriever-ները և vector quantization-ը, և Elastic Cloud-ը ուժեղ կառավարվող տարբերակ է․ նրա կոդը հասանելի է AGPL, SSPL կամ Elastic License-ով։ OpenSearch-ը Apache 2.0 է՝ հիմնադրամի ներքո, սերտորեն ինտեգրվում է AWS-ի հետ և ունի իր plugin-ները անվտանգության, alerting-ի և vector որոնման համար։ Եթե խորապես AWS-ում եք և ուզում եք կառավարվող ծառայություն թույլատրող լիցենզիայով, OpenSearch-ը բնական ընտրություն է։ Եթե ուզում եք որոնման ամենանոր ֆունկցիաները կամ Elastic observability stack-ը, ընտրեք Elasticsearch-ը։ Մի խառնեք նրանց client-ները․ API-ները բավականաչափ տարբերվել են, որ նուրբ bug-եր առաջացնեն։
Բառարան
- Inverted index
- Քարտեզ յուրաքանչյուր term-ից դեպի այն պարունակող փաստաթղթերի ցուցակը, ինչը տեքստային որոնումն արագ է դարձնում։
- Analyzer
- Pipeline-ը, որը տեքստը վերածում է term-երի՝ character filter-ներ, tokenizer և token filter-ներ։
- Mapping
- Ինդեքսի սխեման՝ դաշտերի անուններ, տիպեր և analyzer-ներ։
- Shard
- Ինդեքսի մի հատված, որն ինքնին ամբողջական Lucene ինդեքս է․ primary-ները պահում են տվյալները, replica-ները պատճենում են դրանք։
- BM25
- Լռելյայն relevance բանաձևը՝ հիմնված term-ի հաճախականության, term-ի հազվադեպության և դաշտի երկարության վրա։
- Refresh
- Գործողությունը, որը նոր ինդեքսավորված փաստաթղթերը դարձնում է որոնելի, լռելյայն ամեն վայրկյան։
- Alias
- Կայուն անուն, որը մատնացույց է անում մեկ կամ մի քանի ինդեքս և օգտագործվում է ինդեքսները առանց downtime-ի փոխարինելու համար։
- ILM
- Index lifecycle management՝ ժամանակային ինդեքսների ավտոմատ rollover, tiering և ջնջում։
- RRF
- Reciprocal rank fusion՝ դասակարգված ցուցակների միավորում ըստ դիրքի, որն օգտագործվում է hybrid keyword և vector որոնման համար։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։