สรุปย่อ (TL;DR)
API ของ Elasticsearch ช่วยให้คุณค้นหาและวิเคราะห์ข้อมูลขนาดใหญ่ได้อย่างมีประสิทธิภาพ จัดการเอกสารแบบ JSON ค้นหาด้วย DSL และใช้การรวบรวมผลลัพธ์เพื่อวิเคราะห์ รองรับการยืนยันตัวตนแบบ API keys หรือ basic auth แนะนำให้ใช้ Apidog เพื่อตรวจสอบ mapping, ทดสอบ query และดีบัก aggregation ก่อนขึ้น production
บทนำ
Elasticsearch คือ search/analytics engine แบบ distributed รองรับข้อมูลข้อความที่มีโครงสร้าง, logs, metrics และอื่นๆ เหมาะกับการค้นหาแบบ full-text ในแอป, วิเคราะห์ logs เพื่อ debug และสร้าง dashboard analytics แบบ real-time
Elasticsearch เป็นหัวใจของ ELK Stack (Elasticsearch, Logstash, Kibana) แต่ใช้งานตรงผ่าน API ได้โดยไม่ต้องใช้ Logstash
💡 หากคุณพัฒนา search หรือ log analytics, Apidog ช่วยให้ทดสอบ query, ตรวจสอบ mapping และดีบัก aggregation ได้ง่าย แชร์ template กับทีมได้
ทดสอบ Elasticsearch API ด้วย Apidog - ฟรี
เมื่อจบบทความนี้คุณจะสามารถ:
- จัดทำและจัดการเอกสาร
- เขียน query ด้วย Elasticsearch DSL
- ใช้ aggregation เพื่อวิเคราะห์ข้อมูล
- กำหนด mapping และ analyzer
- ตรวจสอบสุขภาพคลัสเตอร์
เริ่มต้นใช้งาน
เรียกใช้ Elasticsearch บนเครื่องของคุณ
# Docker
docker run -p 9200:9200 \
-e "discovery.type=single-node" \
elasticsearch:8.11.0
# หรือดาวน์โหลดจาก elastic.co
ตรวจสอบการติดตั้ง
curl -X GET "http://localhost:9200"
ตัวอย่าง response:
{
"name": "elasticsearch-1",
"cluster_name": "elasticsearch",
"cluster_uuid": "abc123",
"version": {
"number": "8.11.0",
"build_flavor": "default"
},
"tagline": "You know, for search"
}
การยืนยันตัวตน
Elasticsearch 8.x ต้องการ authentication เป็นค่าเริ่มต้น:
curl -X GET "http://localhost:9200/_cluster/health" \
-u elastic:your_password
หรือใช้ API keys (สร้างใน Kibana หรือผ่าน API)
ดัชนีและเอกสาร
สร้างดัชนี
curl -X PUT "http://localhost:9200/products" \
-u elastic:your_password \
-H "Content-Type: application/json" \
-d '{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"name": { "type": "text" },
"price": { "type": "float" },
"category": { "type": "keyword" },
"in_stock": { "type": "boolean" },
"created_at": { "type": "date" }
}
}
}'
จัดทำเอกสาร
curl -X POST "http://localhost:9200/products/_doc" \
-u elastic:your_password \
-H "Content-Type: application/json" \
-d '{
"name": "Wireless Headphones",
"price": 79.99,
"category": "electronics",
"in_stock": true,
"created_at": "2026-03-24T10:00:00Z"
}'
ตัวอย่าง response:
{
"_index": "products",
"_id": "abc123",
"_version": 1,
"result": "created",
"_seq_no": 0,
"_primary_term": 1
}
ดึงข้อมูลเอกสาร
curl -X GET "http://localhost:9200/products/_doc/abc123" \
-u elastic:your_password
อัปเดตเอกสาร
curl -X PUT "http://localhost:9200/products/_doc/abc123" \
-u elastic:your_password \
-H "Content-Type: application/json" \
-d '{
"name": "Wireless Headphones Pro",
"price": 99.99,
"category": "electronics",
"in_stock": true,
"created_at": "2026-03-24T10:00:00Z"
}'
ลบเอกสาร
curl -X DELETE "http://localhost:9200/products/_doc/abc123" \
-u elastic:your_password
การดำเนินการแบบกลุ่ม (bulk)
จัดทำเอกสารหลายฉบับในคำสั่งเดียว:
curl -X POST "http://localhost:9200/products/_bulk" \
-u elastic:your_password \
-H "Content-Type: application/x-ndjson" \
-d '{"index":{"_id":"1"}}
{"name":"Product A","price":10.99,"category":"books","in_stock":true}
{"index":{"_id":"2"}}
{"name":"Product B","price":20.99,"category":"electronics","in_stock":false}
'
การค้นหา
การค้นหาพื้นฐาน
curl -X GET "http://localhost:9200/products/_search" \
-u elastic:your_password \
-H "Content-Type: application/json" \
-d '{
"query": {
"match": {
"name": "headphones"
}
}
}'
การค้นหาแบบ Bool
รวมเงื่อนไขหลายข้อ:
{
"query": {
"bool": {
"must": [
{ "match": { "name": "headphones" } }
],
"filter": [
{ "term": { "category": "electronics" } },
{ "range": { "price": { "lte": 100 } } },
{ "term": { "in_stock": true } }
]
}
}
}
การค้นหาแบบเต็มข้อความพร้อมการให้คะแนน
{
"query": {
"multi_match": {
"query": "wireless audio headphones",
"fields": ["name^2", "description"],
"type": "best_fields",
"fuzziness": "AUTO"
}
}
}
name^2 หมายถึงให้ field name มีน้ำหนักคะแนนสูงขึ้น
การค้นหาวลี
ค้นหาวลีที่ตรงกันเป๊ะ:
{
"query": {
"match_phrase": {
"description": "noise canceling"
}
}
}
Wildcard และ Regex
{
"query": {
"wildcard": {
"name": "*headphone*"
}
}
}
การเรียงลำดับ
{
"query": { "match_all": {} },
"sort": [
{ "price": "asc" },
{ "_score": "desc" }
]
}
การแบ่งหน้า (pagination)
{
"from": 20,
"size": 10,
"query": { "match_all": {} }
}
การรวบรวมข้อมูล (Aggregation)
Aggregation ใช้สรุปและวิเคราะห์ข้อมูล
ราคาเฉลี่ยตามหมวดหมู่
curl -X GET "http://localhost:9200/products/_search" \
-u elastic:your_password \
-H "Content-Type: application/json" \
-d '{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category" },
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"min_price": { "min": { "field": "price" } },
"max_price": { "max": { "field": "price" } }
}
}
}
}'
ฮิสโตแกรมของราคา
{
"size": 0,
"aggs": {
"price_histogram": {
"histogram": {
"field": "price",
"interval": 25
}
}
}
}
ฮิสโตแกรมวันที่
{
"size": 0,
"aggs": {
"sales_over_time": {
"date_histogram": {
"field": "created_at",
"calendar_interval": "month"
}
}
}
}
Cardinality (นับจำนวนค่าที่ไม่ซ้ำ)
{
"size": 0,
"aggs": {
"unique_categories": {
"cardinality": { "field": "category" }
}
}
}
การแมป (Mapping) และตัววิเคราะห์ (Analyzer)
ประเภทฟิลด์
| ประเภท | ใช้สำหรับ |
|---|---|
text |
ค้นหาข้อความเต็ม, วิเคราะห์แล้ว |
keyword |
ค่าที่แน่นอน, การกรอง, การเรียงลำดับ |
integer, float
|
ตัวเลข |
boolean |
จริง/เท็จ |
date |
วันที่และเวลา |
object |
JSON object ซ้อน |
nested |
อาร์เรย์ของ object (รักษาความสัมพันธ์) |
geo_point |
พิกัด latitude/longitude |
ตัววิเคราะห์แบบกำหนดเอง (Custom Analyzer)
สำหรับ autocomplete:
{
"settings": {
"analysis": {
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "autocomplete_filter"]
}
},
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 20
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard"
}
}
}
}
การจัดการคลัสเตอร์
ตรวจสอบสุขภาพคลัสเตอร์
curl -X GET "http://localhost:9200/_cluster/health"
ตัวอย่าง response:
{
"cluster_name": "elasticsearch",
"status": "green",
"number_of_nodes": 3,
"active_primary_shards": 25
}
- green: shard ทั้งหมดพร้อมใช้งาน
- yellow: replica shard ไม่ครบ (เช่น single-node)
- red: ขาด primary shard
สถิติดัชนี
curl -X GET "http://localhost:9200/_cat/indices?v"
สถิติโหนด
curl -X GET "http://localhost:9200/_nodes/stats"
ล้าง cache
curl -X POST "http://localhost:9200/_cache/clear"
การทดสอบด้วย Apidog
การค้นหาใน Elasticsearch อาจซับซ้อน ควรทดสอบอย่างละเอียด
1. บันทึกการค้นหาที่ใช้บ่อย
สร้าง template query ใน Apidog:
{
"query": {
"bool": {
"must": [
{ "match": { "{{search_field}}": "{{search_term}}" } }
],
"filter": [
{ "range": { "{{price_field}}": { "lte": "{{max_price}}" } } }
]
}
}
}
2. ตรวจสอบการตอบกลับ
pm.test('Search returns results', () => {
const response = pm.response.json()
pm.expect(response.hits.total.value).to.be.above(0)
})
pm.test('Aggregations present', () => {
const response = pm.response.json()
pm.expect(response.aggregations).to.exist
})
3. การแยกสภาพแวดล้อม
# โลคัล
ES_HOST: http://localhost:9200
ES_USER: elastic
ES_PASSWORD: your_password
# การผลิต
ES_HOST: https://search.yourcompany.com
ES_API_KEY: prod_api_key
ทดสอบ Elasticsearch API ด้วย Apidog - ฟรี
ข้อผิดพลาดทั่วไปและการแก้ไข
403 Forbidden
สาเหตุ: authentication ล้มเหลวหรือสิทธิ์ไม่พอ
วิธีแก้ไข: ตรวจสอบ credential, ตรวจสอบว่า API key มีสิทธิ์กับ index
404 index_not_found_exception
สาเหตุ: index ไม่มีอยู่
วิธีแก้ไข: สร้าง index ก่อน หรือเปิด auto-create (ค่า default เปิดอยู่แต่ไม่แนะนำ production)
circuit_breaking_exception
สาเหตุ: ใช้หน่วยความจำมากเกิน
วิธีแก้ไข: ลด size, ทำ query ให้ง่ายขึ้น, เพิ่ม filter
search_phase_execution_exception
สาเหตุ: query syntax error
วิธีแก้ไข: ตรวจสอบ JSON, ระวังเครื่องหมายคำพูดหรือ path field ผิด
ทางเลือกและการเปรียบเทียบ
| คุณสมบัติ | Elasticsearch | OpenSearch | Meilisearch | Typesense |
|---|---|---|---|---|
| การติดตั้ง | โฮสต์เอง | โฮสต์เอง | ไบนารีเดียว | ไบนารีเดียว |
| คุณภาพการค้นหา | ยอดเยี่ยม | ดี | ยอดเยี่ยม | ดี |
| ความยากในการเรียนรู้ | สูงชัน | สูงชัน | ง่าย | ง่าย |
| ความสามารถในการปรับขนาด | ยอดเยี่ยม | ยอดเยี่ยม | ดี | ดี |
| บริการคลาวด์ | Elastic Cloud | OpenSearch Serverless | Meilisearch Cloud | Typesense Cloud |
Elasticsearch มีฟีเจอร์และ community ใหญ่ที่สุด Meilisearch/Typesense เหมาะสำหรับ use case ค้นหาพื้นฐาน
กรณีการใช้งานจริง
การค้นหาสำหรับอีคอมเมิร์ซ:
เว็บไซต์ค้าปลีกจัดทำดัชนีสินค้า 100,000 รายการ ผู้ใช้ค้นหาตามชื่อ คำอธิบาย หมวดหมู่ และช่วงราคา ระบบ autocomplete แนะนำสินค้าและ filter ผลลัพธ์
บันทึกแอปพลิเคชัน:
DevOps ส่ง log เข้า Elasticsearch ผ่าน Filebeat วิศวกรค้นหาตาม service, severity, time แดชบอร์ดแสดง error rate และ response time
การวิเคราะห์ความปลอดภัย:
ทีม security index network logs, ค้นหา IP น่าสงสัย, visualize traffic patterns, แจ้งเตือน anomaly ด้วย aggregation
สรุป
สิ่งที่คุณได้เรียนรู้:
- จัดทำเอกสารเป็น JSON
- เขียน query ด้วย Elasticsearch DSL
- ใช้ aggregation วิเคราะห์ข้อมูล
- กำหนด mapping เพื่อ search ที่ดีที่สุด
- ตรวจสอบสุขภาพคลัสเตอร์
ขั้นตอนถัดไป:
- รัน Elasticsearch บนเครื่อง
- สร้าง index พร้อม mapping
- index ข้อมูลทดสอบ
- เขียน query สำหรับค้นหา
- ทดลอง aggregation
ทดสอบ Elasticsearch API ด้วย Apidog - ฟรี
คำถามที่พบบ่อย
ความแตกต่างระหว่าง Elasticsearch และ Solr คืออะไร?
ทั้งคู่ใช้ Lucene เป็น backend, แต่ Elasticsearch ออกแบบแบบ distributed API ดีกว่า ส่วน Solr มีฟีเจอร์ enterprise มากกว่า โครงการใหม่มักเลือก Elasticsearch
จะ handle อักขระพิเศษในการค้นหาอย่างไร?
Escape อักขระเหล่านี้: ()[]{}:^"\+-!~*?| ด้วย backslash หรือใช้ simple_query_string ที่ tolerant กว่า
Shards คืออะไร?
Shard คือส่วนย่อยของ index แต่ละ shard คือ Lucene index, primary shard สำหรับเขียน, replica shard สำหรับอ่าน/ทนต่อความผิดพลาด
ควรสร้าง shard กี่อัน?
แนะนำ 20-50GB ต่อ shard เริ่ม 1 primary shard + replica shard เพิ่ม primary shard เมื่อจำเป็น (ลดจำนวน primary shard ไม่ได้)
เปลี่ยน mapping หลังจาก index แล้วได้ไหม?
เพิ่ม field ใหม่ได้ ถ้าจะเปลี่ยน type เดิมต้อง reindex ใช้ index template เพื่อ consistency
_routing คืออะไร?
กำหนดเส้นทางเอกสารไปยัง shard ตามค่าฟิลด์ (default: _id) ใช้ routing กับ field ที่ต้อง filter เสมอ เช่น user_id เพื่อ performance
จะ handle ข้อมูลตามเวลา (time-series) อย่างไร?
ตั้งชื่อ index ตามวัน เช่น logs-2026.03.24 จะลบข้อมูลเก่าได้ง่ายขึ้น และ boost performance โดยค้นหาเฉพาะ index ที่ต้องการ

Top comments (0)