DEV Community

Cover image for วิธีใช้ Elasticsearch API ง่าย ๆ
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

วิธีใช้ Elasticsearch API ง่าย ๆ

สรุปย่อ (TL;DR)

API ของ Elasticsearch ช่วยให้คุณค้นหาและวิเคราะห์ข้อมูลขนาดใหญ่ได้อย่างมีประสิทธิภาพ จัดการเอกสารแบบ JSON ค้นหาด้วย DSL และใช้การรวบรวมผลลัพธ์เพื่อวิเคราะห์ รองรับการยืนยันตัวตนแบบ API keys หรือ basic auth แนะนำให้ใช้ Apidog เพื่อตรวจสอบ mapping, ทดสอบ query และดีบัก aggregation ก่อนขึ้น production

ทดลองใช้ Apidog วันนี้

บทนำ

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
Enter fullscreen mode Exit fullscreen mode

ตรวจสอบการติดตั้ง

curl -X GET "http://localhost:9200"
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง response:

{
  "name": "elasticsearch-1",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "abc123",
  "version": {
    "number": "8.11.0",
    "build_flavor": "default"
  },
  "tagline": "You know, for search"
}
Enter fullscreen mode Exit fullscreen mode

การยืนยันตัวตน

Elasticsearch 8.x ต้องการ authentication เป็นค่าเริ่มต้น:

curl -X GET "http://localhost:9200/_cluster/health" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

หรือใช้ 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" }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

จัดทำเอกสาร

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"
  }'
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง response:

{
  "_index": "products",
  "_id": "abc123",
  "_version": 1,
  "result": "created",
  "_seq_no": 0,
  "_primary_term": 1
}
Enter fullscreen mode Exit fullscreen mode

ดึงข้อมูลเอกสาร

curl -X GET "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

อัปเดตเอกสาร

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"
  }'
Enter fullscreen mode Exit fullscreen mode

ลบเอกสาร

curl -X DELETE "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

การดำเนินการแบบกลุ่ม (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}
'
Enter fullscreen mode Exit fullscreen mode

การค้นหา

การค้นหาพื้นฐาน

curl -X GET "http://localhost:9200/products/_search" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "match": {
        "name": "headphones"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

การค้นหาแบบ Bool

รวมเงื่อนไขหลายข้อ:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "headphones" } }
      ],
      "filter": [
        { "term": { "category": "electronics" } },
        { "range": { "price": { "lte": 100 } } },
        { "term": { "in_stock": true } }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

การค้นหาแบบเต็มข้อความพร้อมการให้คะแนน

{
  "query": {
    "multi_match": {
      "query": "wireless audio headphones",
      "fields": ["name^2", "description"],
      "type": "best_fields",
      "fuzziness": "AUTO"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

name^2 หมายถึงให้ field name มีน้ำหนักคะแนนสูงขึ้น

การค้นหาวลี

ค้นหาวลีที่ตรงกันเป๊ะ:

{
  "query": {
    "match_phrase": {
      "description": "noise canceling"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Wildcard และ Regex

{
  "query": {
    "wildcard": {
      "name": "*headphone*"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

การเรียงลำดับ

{
  "query": { "match_all": {} },
  "sort": [
    { "price": "asc" },
    { "_score": "desc" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

การแบ่งหน้า (pagination)

{
  "from": 20,
  "size": 10,
  "query": { "match_all": {} }
}
Enter fullscreen mode Exit fullscreen mode

การรวบรวมข้อมูล (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" } }
        }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

ฮิสโตแกรมของราคา

{
  "size": 0,
  "aggs": {
    "price_histogram": {
      "histogram": {
        "field": "price",
        "interval": 25
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

ฮิสโตแกรมวันที่

{
  "size": 0,
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "month"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cardinality (นับจำนวนค่าที่ไม่ซ้ำ)

{
  "size": 0,
  "aggs": {
    "unique_categories": {
      "cardinality": { "field": "category" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

การแมป (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"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

การจัดการคลัสเตอร์

ตรวจสอบสุขภาพคลัสเตอร์

curl -X GET "http://localhost:9200/_cluster/health"
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง response:

{
  "cluster_name": "elasticsearch",
  "status": "green",
  "number_of_nodes": 3,
  "active_primary_shards": 25
}
Enter fullscreen mode Exit fullscreen mode
  • green: shard ทั้งหมดพร้อมใช้งาน
  • yellow: replica shard ไม่ครบ (เช่น single-node)
  • red: ขาด primary shard

สถิติดัชนี

curl -X GET "http://localhost:9200/_cat/indices?v"
Enter fullscreen mode Exit fullscreen mode

สถิติโหนด

curl -X GET "http://localhost:9200/_nodes/stats"
Enter fullscreen mode Exit fullscreen mode

ล้าง cache

curl -X POST "http://localhost:9200/_cache/clear"
Enter fullscreen mode Exit fullscreen mode

การทดสอบด้วย Apidog

การค้นหาใน Elasticsearch อาจซับซ้อน ควรทดสอบอย่างละเอียด

Elasticsearch API testing in Apidog

1. บันทึกการค้นหาที่ใช้บ่อย

สร้าง template query ใน Apidog:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "{{search_field}}": "{{search_term}}" } }
      ],
      "filter": [
        { "range": { "{{price_field}}": { "lte": "{{max_price}}" } } }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
})
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

ทดสอบ 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 ที่ดีที่สุด
  • ตรวจสอบสุขภาพคลัสเตอร์

ขั้นตอนถัดไป:

  1. รัน Elasticsearch บนเครื่อง
  2. สร้าง index พร้อม mapping
  3. index ข้อมูลทดสอบ
  4. เขียน query สำหรับค้นหา
  5. ทดลอง 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)