Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ค้นหาข้อความแบบเต็มด้วย Elasticsearch ใน Rails

Elasticsearch เป็นหนึ่งในเครื่องมือค้นหาที่ได้รับความนิยมมากที่สุด ในบรรดาบริษัทใหญ่ๆ จำนวนมากที่ชื่นชอบและใช้งานมันอย่างแข็งขันในการผลิต มีบริษัทยักษ์ใหญ่อย่าง Netflix, Medium, GitHub

Elasticsearch มีประสิทธิภาพมาก โดยมีกรณีการใช้งานหลักที่มีการค้นหาข้อความแบบเต็ม บันทึกแบบเรียลไทม์ และการวิเคราะห์ความปลอดภัย

น่าเสียดายที่ Elasticsearch ไม่ค่อยได้รับความสนใจจากชุมชน Rails มากนัก บทความนี้จึงพยายามเปลี่ยนแปลงสิ่งนี้โดยคำนึงถึงสองเป้าหมาย:แนะนำให้ผู้อ่านรู้จักกับแนวคิดของ Elasticsearch และแสดงวิธีใช้งานกับ Ruby on Rails

คุณสามารถค้นหาซอร์สโค้ดของโครงการตัวอย่างที่เราจะสร้างได้ที่นี่ ประวัติการคอมมิตนั้นสอดคล้องกับลำดับของหัวข้อในบทความนี้มากหรือน้อย

แนะนำตัว

จากมุมมองที่กว้างขึ้น Elasticsearch เป็นเครื่องมือค้นหาที่

  • ถูกสร้างขึ้นบน Apache Lucene;
  • จัดเก็บและจัดทำดัชนีเอกสาร JSON อย่างมีประสิทธิภาพ
  • เป็นโอเพ่นซอร์ส
  • จัดเตรียมชุดของ REST API สำหรับการโต้ตอบกับมัน
  • โดยค่าเริ่มต้นไม่มีการรักษาความปลอดภัย (ทุกคนสามารถสอบถามผ่านปลายทางสาธารณะ)
  • สเกลในแนวนอนค่อนข้างดี

มาดูแนวคิดพื้นฐานบางส่วนกัน

ด้วย Elasticsearch เราใส่เอกสารลงในดัชนี ซึ่งจะถูกสืบค้นข้อมูล

ดัชนี คล้ายกับตารางในฐานข้อมูลเชิงสัมพันธ์ เป็นร้านที่เราใส่ เอกสาร (แถว) ที่สามารถสืบค้นภายหลังได้

เอกสาร คือชุดของเขตข้อมูล (คล้ายกับแถวในฐานข้อมูลเชิงสัมพันธ์)

แผนที่ ก็เหมือนนิยามสคีมาในฐานข้อมูลเชิงสัมพันธ์ การทำแผนที่สามารถกำหนดได้อย่างชัดเจนหรือคาดเดาโดย Elasticsearch ในเวลาที่แทรก การกำหนดการแมปดัชนีล่วงหน้าจะดีกว่าเสมอ

ตอนนี้เรามาตั้งค่าสภาพแวดล้อมของเรากันดีกว่า

การติดตั้ง Elasticsearch

วิธีที่ง่ายที่สุดในการติดตั้ง Elasticsearch บน macOS คือการใช้ brew:

brew tap elastic/tap
brew install elastic/tap/elasticsearch-full

อีกทางเลือกหนึ่ง เราสามารถเรียกใช้ผ่าน docker:

docker run \
  -p 127.0.0.1:9200:9200 \
  -p 127.0.0.1:9300:9300 \
  -e "discovery.type=single-node" \
  docker.elastic.co/elasticsearch/elasticsearch:7.16.2

โปรดดูข้อมูลอ้างอิงอย่างเป็นทางการสำหรับตัวเลือกอื่นๆ

Elasticsearch ยอมรับคำขอบนพอร์ต 9200 โดยค่าเริ่มต้น คุณสามารถตรวจสอบว่ามันทำงานด้วยการร้องขอ curl ง่ายๆ (หรือเปิดในเบราว์เซอร์):

curl https://localhost:9200

API

Elasticsearch จัดเตรียมชุดของ REST API เพื่อโต้ตอบกับงานทุกประเภทที่เป็นไปได้ ตัวอย่างเช่น สมมติว่าเราเรียกใช้คำขอ POST ด้วยประเภทเนื้อหา JSON เพื่อสร้างเอกสาร:

curl -X POST https://localhost:9200/my-index/_doc \
  -H 'Content-Type: application/json' \
  -d '{"title": "Banana Cake"}'

ในกรณีนี้ my-index คือชื่อของดัชนี (หากไม่มีอยู่ ดัชนีจะถูกสร้างขึ้นโดยอัตโนมัติ)

_doc เป็นเส้นทางของระบบ (เส้นทางระบบทั้งหมดเริ่มต้นด้วยขีดล่าง)

มีหลายวิธีในการโต้ตอบกับ API

  1. การใช้ curl จากบรรทัดคำสั่ง (คุณอาจพบว่า jq มีประโยชน์)
  2. การเรียกใช้ GET เคียวรีจากเบราว์เซอร์โดยใช้ส่วนขยายบางอย่างสำหรับการพิมพ์ JSON ที่สวยงาม
  3. การติดตั้ง Kibana และการใช้คอนโซล Dev Tools ซึ่งเป็นวิธีโปรดของฉัน
  4. ในที่สุดก็มีส่วนขยาย Chrome ที่ยอดเยี่ยมด้วย

เพื่อประโยชน์ของบทความนี้ ไม่สำคัญว่าคุณจะเลือกอันไหน เราจะไม่โต้ตอบกับ API โดยตรงอยู่ดี เราจะใช้อัญมณีซึ่งพูดคุยกับ REST API แทน

การเริ่มต้นแอปใหม่

แนวคิดคือการสร้างแอปพลิเคชั่นเนื้อเพลงโดยใช้ชุดข้อมูลสาธารณะที่มีเพลงมากกว่า 26K+ แต่ละเพลงจะมีช่องชื่อ ศิลปิน ประเภท และข้อความ เราจะใช้ Elasticsearch สำหรับการค้นหาข้อความแบบเต็ม

เริ่มต้นด้วยการสร้างแอปพลิเคชัน Rails อย่างง่าย:

rails new songs_api --api -d postgresql

เนื่องจากเราจะใช้เป็น API เท่านั้น เราจึงจัดเตรียม --api ตั้งค่าสถานะเพื่อจำกัดชุดมิดเดิลแวร์ที่ใช้

มาสร้างแอปของเรากันเถอะ:

bin/rails generate scaffold Song title:string artist:string genre:string lyrics:text

ตอนนี้ มาเริ่มการย้ายข้อมูลและเริ่มเซิร์ฟเวอร์กัน:

bin/rails db:create db:migrate
bin/rails server

หลังจากนั้น เราตรวจสอบว่าปลายทาง GET ใช้งานได้:

curl https://localhost:3000/songs

นี่จะคืนค่าอาร์เรย์ว่าง ซึ่งไม่น่าแปลกใจเพราะยังไม่มีข้อมูล

แนะนำ Elasticsearch

มาเพิ่ม Elasticsearch ลงในมิกซ์กัน ในการทำเช่นนั้น เราจะต้องใช้ elasticsearch-model gem มันคือ Elasticsearch gem อย่างเป็นทางการที่รวมเข้ากับโมเดล Rails อย่างดี

เพิ่มสิ่งต่อไปนี้ใน Gemfile . ของคุณ :

gem 'elasticsearch-model'

โดยค่าเริ่มต้น มันจะเชื่อมต่อกับพอร์ต 9200 บน localhost ซึ่งเหมาะกับเราอย่างสมบูรณ์ แต่ถ้าคุณต้องการเปลี่ยนแปลง คุณสามารถเริ่มต้นไคลเอนต์โดย

Song.__elasticsearch__.client = Elasticsearch::Client.new host: 'myserver.com', port: 9876

ต่อไป ในการทำให้โมเดลของเราสามารถจัดทำดัชนีโดย Elasticsearch เราต้องทำสองสิ่ง อันดับแรก เราต้องเตรียมการทำแผนที่ (ซึ่งโดยพื้นฐานแล้วเป็นการบอก Elasticsearch เกี่ยวกับโครงสร้างข้อมูลของเรา) และประการที่สอง เราควรสร้างคำขอค้นหา อัญมณีของเราทำได้ทั้งสองอย่าง ไปดูวิธีใช้งานกันเลย

เป็นความคิดที่ดีเสมอที่จะเก็บโค้ดที่เกี่ยวข้องกับ Elastisearch ไว้ในโมดูลที่แยกจากกัน ดังนั้นเรามาสร้างข้อกังวลที่ app/models/concerns/searchable.rb และเพิ่ม

# app/models/concerns/searchable.rb

module Searchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks

    mapping do
      # mapping definition goes here
    end

    def self.search(query)
      # build and run search
    end
  end
end

แม้จะเป็นเพียงโครงกระดูก แต่ก็มีของให้แกะที่นี่

สิ่งแรกและที่สำคัญที่สุดคือ Elasticsearch::Model ซึ่งเพิ่มฟังก์ชันบางอย่างสำหรับการโต้ตอบกับ ES Elasticsearch::Model::Callbacks โมดูลช่วยให้มั่นใจว่าเมื่อเราอัปเดตบันทึก จะอัปเดตข้อมูลใน Elasticsearch โดยอัตโนมัติ mapping block คือที่ที่เราใส่การทำแผนที่ดัชนี Elasticsearch ซึ่งกำหนดว่าฟิลด์ใดจะถูกเก็บไว้ใน Elasticsearch และควรมีประเภทใด ในที่สุดก็มี search วิธีที่เราจะใช้ในการค้นหาเนื้อเพลงของ Elasticsearch อัญมณีที่เราใช้ให้ search เมธอดที่สามารถใช้กับข้อความค้นหาง่ายๆ เช่น Song.search("genesis”) แต่เราจะใช้กับคำค้นหาที่ซับซ้อนมากขึ้นซึ่งสร้างโดยใช้ข้อความค้นหา DSL (เพิ่มเติมในภายหลัง)

อย่าลืมใส่ข้อกังวลในคลาสโมเดลของเรา:

# /app/models/song.rb

class Song < ApplicationRecord
  include Searchable
end

การจับคู่

ใน Elasticsearch การทำแผนที่เปรียบเสมือนคำจำกัดความของสคีมาในฐานข้อมูลเชิงสัมพันธ์ เราอธิบายโครงสร้างของเอกสารที่เราต้องการจัดเก็บ ต่างจากฐานข้อมูลเชิงสัมพันธ์ทั่วไป เราไม่จำเป็นต้องกำหนดแผนที่ล่วงหน้า:Elasticsearch จะพยายามคาดเดาประเภทให้เราอย่างเต็มที่ อย่างไรก็ตาม เนื่องจากเราไม่ต้องการความประหลาดใจใดๆ เราจะกำหนดแผนที่ของเราไว้ล่วงหน้าอย่างชัดแจ้ง

สามารถอัปเดตการแมปผ่านปลายทาง REST โดยใช้ PUT /my-index/_mapping และอ่านผ่าน GET /my-index/_mapping แต่ elasticsearch gem abstracts สำหรับเรา สิ่งที่เราต้องทำคือจัดเตรียม mapping บล็อก:

# app/models/concerns/searchable.rb

mapping do
  indexes :artist, type: :text
  indexes :title, type: :text
  indexes :lyrics, type: :text
  indexes :genre, type: :keyword
end

เรากำลังจะสร้างดัชนี artist , title และ lyrics ฟิลด์ที่ใช้ประเภทข้อความ เป็นประเภทเดียวที่จัดทำดัชนีสำหรับการค้นหาข้อความแบบเต็ม สำหรับ genre เราจะใช้ประเภทคำหลักซึ่งเป็นการค้นหาในอุดมคติที่กรองด้วยค่าที่แน่นอน

ตอนนี้เรียกใช้คอนโซล rails ด้วย bin/rails console แล้วรัน

Song.__elasticsearch__.create_index!

สิ่งนี้จะสร้างดัชนีของเราใน Elasticsearch __elasticsearch__ วัตถุคือประตูสู่โลกของ Elasticsearch ซึ่งอัดแน่นไปด้วยวิธีการที่มีประโยชน์มากมายสำหรับการโต้ตอบกับ Elasticsearch

การนำเข้าข้อมูล

ทุกครั้งที่เราสร้างบันทึก มันจะส่งข้อมูลไปยัง Elasticsearch โดยอัตโนมัติ ดังนั้น เราจะดาวน์โหลดชุดข้อมูลที่มีเนื้อเพลงและนำเข้าไปยังแอพของเรา ขั้นแรก ดาวน์โหลดจากลิงค์นี้ (ชุดข้อมูลภายใต้ Creative Commons Attribution 4.0 International license ). ไฟล์ CSV นี้มีบันทึกมากกว่า 26,000 รายการ ซึ่งเราจะนำเข้าไปยังฐานข้อมูลและ Elasticsearch ของเราด้วยรหัสด้านล่าง:

require 'csv'

class Song < ApplicationRecord
  include Searchable

  def self.import_csv!
    filepath = "/path/to/your/file/tcc_ceds_music.csv"
    res = CSV.parse(File.read(filepath), headers: true)
    res.each_with_index do |s, ind|
      Song.create!(
        artist: s["artist_name"],
        title: s["track_name"],
        genre: s["genre"],
        lyrics: s["lyrics"]
      )
    end
  end
end

เปิดคอนโซลรางและเรียกใช้ Song.import_csv! (จะใช้เวลาสักครู่) อีกทางหนึ่ง เราสามารถนำเข้าข้อมูลจำนวนมาก ซึ่งเร็วกว่ามาก แต่ในกรณีนี้ เราต้องการให้แน่ใจว่าเราสร้างบันทึกในฐานข้อมูล PostgreSQL และ Elasticsearch

เมื่อการนำเข้าเสร็จสิ้น ตอนนี้เรามีเนื้อเพลงมากมายที่เราสามารถค้นหาได้

การค้นหาข้อมูล

elasticsearch-model gem เพิ่ม search วิธีการที่ช่วยให้เราสามารถค้นหาในฟิลด์ที่จัดทำดัชนีทั้งหมด มาใช้ในข้อกังวลที่ค้นหาได้ของเรา:

# app/models/concerns/searchable.rb

# ...
def self.search(query)
  self.__elasticsearch__.search(query)
end
# ...

เปิดคอนโซลรางและเรียกใช้ res = Song.search('genesis') . ออบเจ็กต์การตอบกลับมีข้อมูลเมตาจำนวนมาก:ระยะเวลาในการร้องขอ ใช้โหนดใด ฯลฯ เราสนใจ Hit ที่ res.response["hits"]["hits"] .

มาเปลี่ยน index . ของคอนโทรลเลอร์ของเรากันเถอะ วิธีการสอบถาม ES แทน

# app/controllers/songs_controller.rb

def index
  query = params["query"] || ""
  res = Song.search(query)
  render json: res.response["hits"]["hits"]
end

ตอนนี้เราสามารถลองโหลดในเบราว์เซอร์หรือใช้ curl https://localhost:3000/songs?query=genesis . คำตอบจะมีลักษณะดังนี้:


[
  {
  "_index": "songs",
  "_type": "_doc",
  "_id": "22676",
  "_score": 12.540506,
  "_source": {
    "id": 22676,
    "title": "genesis",
    "artist": "grimes",
    "genre": "pop",
    "lyrics": "heart know heart ...",
    "created_at": "...",
    "updated_at": "..."
    }
  },
...
]

อย่างที่คุณเห็น ข้อมูลจริงถูกส่งกลับภายใต้ _source คีย์ ส่วนช่องอื่นๆ เป็นข้อมูลเมตา ที่สำคัญที่สุดคือ _score แสดงให้เห็นว่าเอกสารมีความเกี่ยวข้องกับการค้นหานั้นอย่างไร เราจะดำเนินการในเร็วๆ นี้ แต่ก่อนอื่น เรามาเรียนรู้วิธีสร้างคำค้นหากันก่อน

แบบสอบถาม DSL

DSL ข้อความค้นหาของ Elasticsearch มีวิธีการสร้างการสืบค้นที่ซับซ้อน และเราสามารถใช้ได้จากรหัส ruby ​​เช่นกัน ตัวอย่างเช่น มาแก้ไขวิธีการค้นหาเพื่อค้นหาเฉพาะช่องศิลปิน:

# app/models/concerns/searchable.rb

module Searchable
  extend ActiveSupport::Concern

  included do
    # ...

    def self.search(query)
      params = {
        query: {
          match: {
            artist: query,
          },
        },
      }

      self.__elasticsearch__.search(params)
    end
  end
end

โครงสร้างการจับคู่ข้อความค้นหาช่วยให้เราสามารถค้นหาเฉพาะฟิลด์เฉพาะ (ในกรณีนี้คือศิลปิน) ตอนนี้ หากเราค้นหาเพลงอีกครั้งด้วย "genesis" (ลองโหลด https://localhost:3000/songs?query=genesis ) เราจะได้เฉพาะเพลงของวง "Genesis" เท่านั้น ไม่ใช่เพลงที่มี "genesis" อยู่ในชื่อ หากเราต้องการสืบค้นข้อมูลหลายช่อง ซึ่งมักจะเป็นกรณีนี้ เราสามารถใช้การสืบค้นแบบหลายรายการได้:

# app/models/concerns/searchable.rb

def self.search(query)
  params = {
    query: {
      multi_match: {
        query: query, 
        fields: [ :title, :artist, :lyrics ] 
      },
    },
  }

  self.__elasticsearch__.search(params)
end

การกรอง

จะเป็นอย่างไรถ้าเราต้องการค้นหาเฉพาะในเพลงร็อค จากนั้นเราต้องกรองตามประเภท! นี่จะทำให้การค้นหาของเราซับซ้อนขึ้นเล็กน้อย แต่ไม่ต้องกังวล เราจะอธิบายทุกอย่างทีละขั้นตอน!

  def self.search(query, genre = nil)
    params = {
      query: {
        bool: {
          must: [
            {
              multi_match: {
                query: query, 
                fields: [ :title, :artist, :lyrics ] 
              }
            },
          ],
          filter: [
            {
              term: { genre: genre }
            }
          ]
        }
      }
    }

    self.__elasticsearch__.search(params)
  end

คำหลักใหม่คำแรกคือ bool ซึ่งเป็นเพียงวิธีการรวมข้อความค้นหาหลายคำเข้าเป็นหนึ่งเดียว ในกรณีของเรา เรากำลังรวม must และ filter . อันแรก (must ) มีส่วนช่วยในการให้คะแนนและมีข้อความค้นหาเดียวกันกับที่เราเคยใช้มาก่อน อันที่สอง (filter ) ไม่ส่งผลต่อคะแนน แต่ทำในสิ่งที่ระบุ:กรองเอกสารที่ไม่ตรงกับคำค้นหาออก เราต้องการกรองบันทึกของเราตามประเภท ดังนั้นเราจึงใช้คำค้นหา

สิ่งสำคัญคือต้องสังเกตว่า filter-term ชุดค่าผสมไม่มีส่วนเกี่ยวข้องกับการค้นหาข้อความแบบเต็ม เป็นเพียงตัวกรองปกติตามค่าที่แน่นอน เช่นเดียวกับ WHERE ประโยคทำงานใน SQL (WHERE genre = 'rock' ). เป็นการดีที่จะรู้วิธีใช้ term การกรอง แต่เราไม่ต้องการมันที่นี่

การให้คะแนน

ผลการค้นหาเรียงตาม _score ที่แสดงให้เห็นว่ารายการมีความเกี่ยวข้องกับการค้นหาเฉพาะอย่างไร ยิ่งคะแนนสูง เอกสารก็ยิ่งมีความเกี่ยวข้องมากขึ้นเท่านั้น คุณอาจสังเกตเห็นว่าเมื่อเราค้นหาคำว่า genesis ผลลัพธ์แรกที่โผล่ขึ้นมาคือเพลงของ Grimes ในขณะที่ฉันสนใจวง Genesis มากกว่า แล้วเราจะปรับเปลี่ยนกลไกการให้คะแนนให้สนใจด้านศิลปินมากขึ้นได้หรือไม่? ใช่ เราทำได้ แต่ในการทำเช่นนั้น เราต้องปรับแต่งการสืบค้นของเราก่อน:

  def self.search(query)
    params = {
      query: {
        bool: {
          should: [
            { match: { title: query }},
            { match: { artist: query }},
            { match: { lyrics: query }},
          ],
        }
      },
    }

    self.__elasticsearch__.search(params)
  end

เคียวรีนี้เทียบเท่ากับอันเดิม ยกเว้นว่าใช้คีย์เวิร์ด bool ซึ่งเป็นเพียงวิธีการรวมการสืบค้นหลายรายการเป็นหนึ่งเดียว เราใช้ should ซึ่งมีสามข้อความค้นหาแยกกัน (หนึ่งรายการต่อฟิลด์):โดยพื้นฐานแล้วจะรวมกันโดยใช้ตรรกะ OR หากเราใช้ must แต่จะรวมกันโดยใช้ตรรกะ AND เหตุใดเราจึงต้องมีการแข่งขันแยกกันในแต่ละสนาม? นั่นเป็นเพราะว่าตอนนี้เราสามารถระบุคุณสมบัติบูสต์ ซึ่งเป็นค่าสัมประสิทธิ์ที่คูณคะแนนจากการสืบค้นเฉพาะ:

  def self.search(query)
    params = {
      query: {
        bool: {
          should: [
            { match: { title: query }},
            { match: { artist: { query: query, boost: 5 } }},
            { match: { lyrics: query }},
          ],
        }
      },
    }

    self.__elasticsearch__.search(params)
  end

สิ่งอื่นที่เท่าเทียมกัน คะแนนของเราจะสูงขึ้นห้าเท่าหากข้อความค้นหาตรงกับศิลปิน ลอง genesis สืบค้นอีกครั้งด้วย https://localhost:3000/songs?query=genesis และคุณจะเห็นเพลงของวง Genesis มาเป็นอันดับแรก หวาน!

ไฮไลต์

คุณสมบัติที่เป็นประโยชน์อีกประการหนึ่งของ Elasticsearch คือสามารถเน้นการจับคู่ภายในเอกสาร ซึ่งทำให้ผู้ใช้เข้าใจได้ดีขึ้นว่าเหตุใดผลลัพธ์จึงปรากฏในการค้นหา

ใน HTML มีแท็ก HTML พิเศษสำหรับสิ่งนั้น และ Elasticsearch สามารถเพิ่มได้โดยอัตโนมัติ

มาเปิด searchable.rb . กันเถอะ กังวลอีกครั้งและเพิ่มคำสำคัญใหม่:

def self.search(query)
  params = {
    query: {
      bool: {
        should: [
          { match: { title: query }},
          { match: { artist: { query: query, boost: 5 } }},
          { match: { lyrics: query }},
        ],
      }
    },
    highlight: { fields: { title: {}, artist: {}, lyrics: {} } }
  }

  self.__elasticsearch__.search(params)
end

highlightใหม่ ฟิลด์ ระบุว่าฟิลด์ใดควรเน้น เราเลือกทั้งหมด ทีนี้ ถ้าเราโหลด https://localhost:3000/query=genesis เราควรจะเห็นช่องใหม่ชื่อว่า "highlight" ซึ่งมีฟิลด์เอกสารที่มีวลีที่ตรงกันอยู่ใน em แท็ก

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเน้น โปรดดูคู่มืออย่างเป็นทางการ

ความคลุมเครือ

เอาล่ะ หากเราเขียน benesis . ผิดพลาด แทน genesis ? สิ่งนี้จะไม่ส่งคืนผลลัพธ์ใดๆ แต่เราสามารถบอก Elasticsearch ให้จู้จี้จุกจิกน้อยลงและอนุญาตการค้นหาที่คลุมเครือ ดังนั้นมันจะแสดง genesis ผลลัพธ์เช่นกัน

นี่คือวิธีการทำ เพียงเปลี่ยนข้อความค้นหาศิลปินจาก { match: { artist: { query: query, boost: 5 } }} เป็น { match: { artist: { query: query, boost: 5, fuzziness: "AUTO" } }} . สามารถกำหนดค่ากลไกความคลุมเครือที่แน่นอนได้ โปรดดูรายละเอียดเพิ่มเติมในเอกสารอย่างเป็นทางการ

จะไปต่อที่ไหน

ฉันหวังว่าบทความนี้จะทำให้คุณเชื่อมั่นว่า Elasticsearch เป็นเครื่องมือที่ทรงพลังที่สามารถใช้ได้และควรใช้เมื่อคุณต้องใช้การค้นหาที่ไม่สำคัญ หากคุณพร้อมที่จะเรียนรู้เพิ่มเติม นี่คือลิงค์ที่เป็นประโยชน์:

ทรัพยากร

  • ข้อมูลอ้างอิงอย่างเป็นทางการของ Elasticsearch
  • อัญมณีทับทิม
  • อัญมณี Rails
  • หนังสือที่ดีมากที่เต็มไปด้วยความรู้เชิงปฏิบัติ
  • สร้างการเติมข้อความอัตโนมัติ

อัญมณีทางเลือก

  • Searchkick
  • เคี้ยวหนึบ