Elasticsearch มีอินเทอร์เฟซ HTTP RESTful ที่มีประสิทธิภาพสำหรับการจัดทำดัชนีและการสืบค้นข้อมูลซึ่งสร้างขึ้นที่ด้านบนของไฟล์ Apache Lucene ห้องสมุด. ทันทีที่แกะออกจากกล่องให้การค้นหาที่ปรับขนาดได้มีประสิทธิภาพและมีประสิทธิภาพพร้อมรองรับ UTF-8 เป็นเครื่องมือที่มีประสิทธิภาพในการจัดทำดัชนีและสืบค้นข้อมูลที่มีโครงสร้างจำนวนมหาศาลและที่นี่ ApeeScape มันเพิ่มพลังให้กับการค้นหาแพลตฟอร์มของเราและในไม่ช้าก็จะถูกใช้สำหรับการเติมข้อความอัตโนมัติเช่นกัน เราเป็นแฟนตัวยง
Chewy ขยายไคลเอนต์ Elasticsearch-Ruby ทำให้มีประสิทธิภาพมากขึ้นและให้การทำงานร่วมกับ Rails ที่เข้มงวดยิ่งขึ้นเนื่องจากแพลตฟอร์มของเราสร้างขึ้นโดยใช้ ทับทิมบนราง การรวม Elasticsearch ของเราใช้ประโยชน์จากไฟล์ ยางยืดค้นหาทับทิม โปรเจ็กต์ (เฟรมเวิร์กการรวม Ruby สำหรับ Elasticsearch ที่ให้ไคลเอนต์สำหรับเชื่อมต่อกับคลัสเตอร์ Elasticsearch, Ruby API สำหรับ REST API ของ Elasticsearch และส่วนขยายและยูทิลิตี้ต่างๆ) จากรากฐานนี้เราได้พัฒนาและเผยแพร่การปรับปรุง (และทำให้ง่ายขึ้น) ของสถาปัตยกรรมการค้นหาแอปพลิเคชัน Elasticsearch ซึ่งบรรจุเป็นอัญมณีทับทิมที่เราตั้งชื่อว่า เคี้ยว (พร้อมแอปตัวอย่าง ที่นี่ ).
Chewy ขยายไคลเอนต์ Elasticsearch-Ruby ทำให้มีประสิทธิภาพมากขึ้นและให้การทำงานร่วมกับ Rails ที่เข้มงวดยิ่งขึ้น ในคู่มือ Elasticsearch นี้ฉันจะพูดถึง (ผ่านตัวอย่างการใช้งาน) ว่าเราทำสิ่งนี้สำเร็จได้อย่างไรรวมถึงอุปสรรคทางเทคนิคที่เกิดขึ้นระหว่างการใช้งาน
cfo หมายถึงอะไรในธุรกิจ
เพียงสองสามบันทึกย่อก่อนดำเนินการตามคำแนะนำ:
แม้จะมีความสามารถในการปรับขนาดและประสิทธิภาพของ Elasticsearch แต่การรวมเข้ากับ Rails ก็ไม่ได้ง่ายอย่างที่คาดไว้ ที่ ApeeScape เราพบว่าตัวเองจำเป็นต้องเพิ่มไคลเอนต์ Elasticsearch-Ruby พื้นฐานอย่างมากเพื่อให้มีประสิทธิภาพมากขึ้นและเพื่อรองรับการดำเนินการเพิ่มเติม
ดังนั้นอัญมณี Chewy จึงถือกำเนิดขึ้น
คุณสมบัติเด่นบางประการของ Chewy ได้แก่ :
ทุกดัชนีสามารถสังเกตได้จากแบบจำลองที่เกี่ยวข้องทั้งหมด
โมเดลที่จัดทำดัชนีส่วนใหญ่มีความสัมพันธ์ซึ่งกันและกัน และบางครั้งก็จำเป็นต้องทำให้ข้อมูลที่เกี่ยวข้องนี้กลายเป็นปกติและผูกเข้ากับออบเจ็กต์เดียวกัน (เช่นหากคุณต้องการจัดทำดัชนีแท็กอาร์เรย์ร่วมกับบทความที่เกี่ยวข้อง) Chewy ช่วยให้คุณระบุดัชนีที่สามารถอัปเดตได้สำหรับทุกรุ่นดังนั้นบทความที่เกี่ยวข้องจะได้รับการจัดทำดัชนีใหม่ทุกครั้งที่มีการอัปเดตแท็กที่เกี่ยวข้อง
คลาสดัชนีเป็นอิสระจากโมเดล ORM / ODM
ด้วยการปรับปรุงนี้การใช้งานการเติมข้อความอัตโนมัติข้ามรุ่นจะง่ายกว่ามาก คุณสามารถกำหนดดัชนีและใช้งานได้ในรูปแบบเชิงวัตถุ แตกต่างจากไคลเอนต์อื่น ๆ Chewy gem ไม่จำเป็นต้องใช้คลาสดัชนีด้วยตนเองการเรียกกลับการนำเข้าข้อมูลและส่วนประกอบอื่น ๆ
การนำเข้าจำนวนมากคือ ทุกที่ .
Chewy ใช้ Elasticsearch API จำนวนมากสำหรับการทำดัชนีและการอัปเดตดัชนีใหม่ทั้งหมด นอกจากนี้ยังใช้แนวคิดของการอัปเดตอะตอมรวบรวมวัตถุที่เปลี่ยนแปลงภายในบล็อกอะตอมและอัปเดตทั้งหมดในครั้งเดียว
Chewy ให้ DSL แบบสอบถามสไตล์ AR
การเพิ่มประสิทธิภาพนี้ช่วยให้สามารถสร้างข้อความค้นหาได้อย่างมีประสิทธิภาพมากขึ้น
เอาล่ะมาดูกันว่าทั้งหมดนี้มีบทบาทอย่างไรในอัญมณี ...
Elasticsearch มีแนวคิดเกี่ยวกับเอกสารหลายประการ อย่างแรกคือ index
(อะนาล็อกของ database
ใน RDBMS ) ซึ่งประกอบด้วยชุดของ documents
ซึ่งมีได้หลายอย่าง types
(โดยที่ a type
เป็นตาราง RDBMS ชนิดหนึ่ง)
เอกสารทุกชุดมี fields
. แต่ละฟิลด์ได้รับการวิเคราะห์อย่างอิสระและตัวเลือกการวิเคราะห์จะถูกเก็บไว้ใน mapping
สำหรับประเภทของมัน Chewy ใช้โครงสร้างนี้“ ตามสภาพ” ในแบบจำลองวัตถุ:
class EntertainmentIndex { author.name } field :author_id, type: 'integer' field :description field :tags, index: 'not_analyzed', value: ->{ tags.map(&:name) } end {movie: Video.movies, cartoon: Video.cartoons}.each do |type_name, scope| define_type scope.includes(:director, :tags), name: type_name do field :title, analyzer: 'title' field :year, type: 'integer' field :author, value: ->{ director.name } field :author_id, type: 'integer', value: ->{ director_id } field :description field :tags, index: 'not_analyzed', value: ->{ tags.map(&:name) } end end end
ด้านบนเรากำหนดดัชนี Elasticsearch ที่เรียกว่า entertainment
มีสามประเภท: book
, movie
และ cartoon
. สำหรับแต่ละประเภทเราได้กำหนดการแมปฟิลด์และแฮชของการตั้งค่าสำหรับดัชนีทั้งหมด
ดังนั้นเราจึงได้กำหนด EntertainmentIndex
และเราต้องการดำเนินการค้นหา ในขั้นตอนแรกเราต้องสร้างดัชนีและนำเข้าข้อมูลของเรา:
EntertainmentIndex.create! EntertainmentIndex.import # EntertainmentIndex.reset! (which includes deletion, # creation, and import) could be used instead
.import
วิธีการรับรู้ข้อมูลที่นำเข้าเนื่องจากเราส่งผ่านขอบเขตเมื่อเรากำหนดประเภทของเรา ดังนั้นมันจะนำเข้าหนังสือภาพยนตร์และการ์ตูนทั้งหมดที่เก็บไว้ในที่จัดเก็บถาวร
เมื่อเสร็จแล้วเราสามารถดำเนินการสอบถามได้:
EntertainmentIndex.query(match: {author: 'Tarantino'}).filter{ year > 1990 } EntertainmentIndex.query(match: {title: 'Shawshank'}).types(:movie) EntertainmentIndex.query(match: {author: 'Tarantino'}).only(:id).limit(10).load # the last one loads ActiveRecord objects for documents found
ตอนนี้ดัชนีของเราเกือบพร้อมที่จะใช้ในการค้นหาของเราแล้ว
สำหรับการรวมกับ Rails สิ่งแรกที่เราต้องมีคือสามารถตอบสนองต่อการเปลี่ยนแปลงวัตถุ RDBMS Chewy รองรับพฤติกรรมนี้ผ่านการเรียกกลับที่กำหนดไว้ภายใน update_index
วิธีการเรียน update_index
รับสองอาร์กิวเมนต์:
c++ รวมไฟล์ cpp อื่น ๆ
'index_name#type_name'
รูปแบบเราจำเป็นต้องกำหนดการเรียกกลับเหล่านี้สำหรับแต่ละรุ่นที่ขึ้นต่อกัน:
class Book เนื่องจากแท็กได้รับการจัดทำดัชนีเราจึงต้องทำการปะติดปะต่อโมเดลภายนอกบางรุ่นเพื่อให้ตอบสนองต่อการเปลี่ยนแปลง:
ActsAsTaggableOn::Tag.class_eval do has_many :books, through: :taggings, source: :taggable, source_type: 'Book' has_many :videos, through: :taggings, source: :taggable, source_type: 'Video' # Updating all tag-related objects update_index 'entertainment#book', :books update_index('entertainment#movie') { videos.movies } update_index('entertainment#cartoon') { videos.cartoons } end ActsAsTaggableOn::Tagging.class_eval do # Same goes for the intermediate model update_index('entertainment#book') { taggable if taggable_type == 'Book' } update_index('entertainment#movie') { taggable if taggable_type == 'Video' && taggable.movie? } update_index('entertainment#cartoon') { taggable if taggable_type == 'Video' && taggable.cartoon? } end
ณ จุดนี้ทุกวัตถุ บันทึก หรือ ทำลาย จะอัปเดตประเภทดัชนี Elasticsearch ที่สอดคล้องกัน
ปรมาณู
เรายังคงมีปัญหาค้างคาอยู่อย่างหนึ่ง ถ้าเราทำสิ่งที่ชอบ books.map(&:save)
หากต้องการบันทึกหนังสือหลายเล่มเราจะขออัปเดต entertainment
ดัชนี ทุกครั้งที่บันทึกหนังสือแต่ละเล่ม . ดังนั้นหากเราบันทึกหนังสือห้าเล่มเราจะอัปเดตดัชนี Chewy ห้าครั้ง พฤติกรรมนี้เป็นที่ยอมรับสำหรับ REPL แต่ไม่สามารถยอมรับได้อย่างแน่นอนสำหรับการกระทำของคอนโทรลเลอร์ซึ่งประสิทธิภาพเป็นสิ่งสำคัญ
เราแก้ไขปัญหานี้ด้วย Chewy.atomic
บล็อก:
class ApplicationController ในระยะสั้น Chewy.atomic
แบทช์อัปเดตเหล่านี้ดังนี้:
- ปิดการใช้งาน
after_save
โทรกลับ. - รวบรวม ID ของหนังสือที่บันทึกไว้
- เมื่อเสร็จสิ้น
Chewy.atomic
บล็อกใช้ ID ที่รวบรวมเพื่อสร้างคำขออัปเดตดัชนี Elasticsearch เดียว
กำลังค้นหา
ตอนนี้เราพร้อมที่จะติดตั้งอินเทอร์เฟซการค้นหาแล้ว เนื่องจากอินเทอร์เฟซผู้ใช้ของเราเป็นรูปแบบหนึ่งวิธีที่ดีที่สุดในการสร้างก็คือด้วย FormBuilder และ ActiveModel . (ที่ ApeeScape เราใช้ ActiveData เพื่อใช้อินเทอร์เฟซ ActiveModel แต่อย่าลังเลที่จะใช้อัญมณีที่คุณชื่นชอบ)
บริษัท c กับ s คอร์ปอเรชั่น
class EntertainmentSearch include ActiveData::Model attribute :query, type: String attribute :author_id, type: Integer attribute :min_year, type: Integer attribute :max_year, type: Integer attribute :tags, mode: :arrayed, type: String, normalize: ->(value) { value.reject(&:blank?) } # This accessor is for the form. It will have a single text field # for comma-separated tag inputs. def tag_list= value self.tags = value.split(',').map(&:strip) end def tag_list self.tags.join(', ') end end
บทช่วยสอนการสืบค้นและตัวกรอง
ตอนนี้เรามีวัตถุคล้าย ActiveModel ที่สามารถยอมรับและพิมพ์แอตทริบิวต์ได้แล้วเรามาใช้การค้นหากัน:
class EntertainmentSearch ... def index EntertainmentIndex end def search # We can merge multiple scopes [query_string, author_id_filter, year_filter, tags_filter].compact.reduce(:merge) end # Using query_string advanced query for the main query input def query_string index.query(query_string: {fields: [:title, :author, :description], query: query, default_operator: 'and'}) if query? end # Simple term filter for author id. `:author_id` is already # typecasted to integer and ignored if empty. def author_id_filter index.filter(term: {author_id: author_id}) if author_id? end # For filtering on years, we will use range filter. # Returns nil if both min_year and max_year are not passed to the model. def year_filter body = {}.tap do |body| body.merge!(gte: min_year) if min_year? body.merge!(lte: max_year) if max_year? end index.filter(range: {year: body}) if body.present? end # Same goes for `author_id_filter`, but `terms` filter used. # Returns nil if no tags passed in. def tags_filter index.filter(terms: {tags: tags}) if tags? end end
ตัวควบคุมและมุมมอง
ณ จุดนี้โมเดลของเราสามารถดำเนินการร้องขอการค้นหาด้วยคุณสมบัติที่ส่งผ่าน การใช้งานจะมีลักษณะดังนี้:
EntertainmentSearch.new(query: 'Tarantino', min_year: 1990).search
โปรดทราบว่าในคอนโทรลเลอร์เราต้องการโหลดอ็อบเจ็กต์ ActiveRecord แทน เคี้ยว เครื่องห่อเอกสาร:
class EntertainmentController ตอนนี้ได้เวลาเขียนบางส่วน แฮมล ที่ entertainment/index.html.haml
:
= form_for @search, as: :search, url: entertainment_index_path, method: :get do |f| = f.text_field :query = f.select :author_id, Dude.all.map d, include_blank: true = f.text_field :min_year = f.text_field :max_year = f.text_field :tag_list = f.submit - if @entertainments.any? %dl - @entertainments.each do |entertainment| %dt %h1= entertainment.title %strong= entertainment.class %dd %p= entertainment.year %p= entertainment.description %p= entertainment.tag_list = paginate @entertainments - else Nothing to see here
การเรียงลำดับ
เพื่อเป็นโบนัสเราจะเพิ่มการจัดเรียงในฟังก์ชันการค้นหาของเราด้วย
สมมติว่าเราจำเป็นต้องเรียงลำดับในฟิลด์ชื่อเรื่องและปีรวมทั้งตามความเกี่ยวข้อง เสียดายชื่อ One Flew Over the Cuckoo's Nest
จะแบ่งออกเป็นแต่ละคำดังนั้นการจัดเรียงตามคำที่แตกต่างกันเหล่านี้จะสุ่มเกินไป แต่เราต้องการจัดเรียงตามชื่อทั้งหมด
วิธีแก้ปัญหาคือการใช้ฟิลด์หัวเรื่องพิเศษและใช้ตัววิเคราะห์ของตัวเอง:
class EntertainmentIndex นอกจากนี้เรากำลังจะเพิ่มทั้งแอตทริบิวต์ใหม่เหล่านี้และขั้นตอนการประมวลผลการจัดเรียงในรูปแบบการค้นหาของเรา:
class EntertainmentSearch # we are going to use `title.sorted` field for sort SORT = {title: {'title.sorted' => :asc}, year: {year: :desc}, relevance: :_score} ... attribute :sort, type: String, enum: %w(title year relevance), default_blank: 'relevance' ... def search # we have added `sorting` scope to merge list [query_string, author_id_filter, year_filter, tags_filter, sorting].compact.reduce(:merge) end def sorting # We have one of the 3 possible values in `sort` attribute # and `SORT` mapping returns actual sorting expression index.order(SORT[sort.to_sym]) end end
สุดท้ายเราจะแก้ไขแบบฟอร์มของเราโดยเพิ่มช่องการเลือกตัวเลือกการจัดเรียง:
= form_for @search, as: :search, url: entertainment_index_path, method: :get do |f| ... / `EntertainmentSearch.sort_values` will just return / enum option content from the sort attribute definition. = f.select :sort, EntertainmentSearch.sort_values ...
การจัดการข้อผิดพลาด
หากผู้ใช้ของคุณดำเนินการค้นหาที่ไม่ถูกต้องเช่น (
หรือ AND
ไคลเอนต์ Elasticsearch จะแสดงข้อผิดพลาด ในการจัดการดังกล่าวเรามาทำการเปลี่ยนแปลงบางอย่างกับตัวควบคุมของเรา:
class EntertainmentController e @entertainments = [] @error = e.message.match(/QueryParsingException[([^;]+)]/).try(:[], 1) end end
นอกจากนี้เราจำเป็นต้องแสดงข้อผิดพลาดในมุมมอง:
... - if @entertainments.any? ... - else - if @error = @error - else Nothing to see here
การทดสอบการสืบค้น Elasticsearch
การตั้งค่าการทดสอบพื้นฐานมีดังนี้:
- เริ่มเซิร์ฟเวอร์ Elasticsearch
- ล้างข้อมูลและสร้างดัชนีของเรา
- นำเข้าข้อมูลของเรา
- ดำเนินการสอบถามของเรา
- อ้างอิงผลลัพธ์กับความคาดหวังของเรา
สำหรับขั้นตอนที่ 1 สะดวกในการใช้คลัสเตอร์การทดสอบที่กำหนดไว้ในไฟล์ ยืดหยุ่น อัญมณี. เพียงเพิ่มบรรทัดต่อไปนี้ใน Rakefile
ของโครงการของคุณ การติดตั้งหลังอัญมณี:
require 'elasticsearch/extensions/test/cluster/tasks'
จากนั้นคุณจะได้รับสิ่งต่อไปนี้ คราด งาน:
$ rake -T elasticsearch rake elasticsearch:start # Start Elasticsearch cluster for tests rake elasticsearch:stop # Stop Elasticsearch cluster for tests
Elasticsearch และ Rspec
ขั้นแรกเราต้องตรวจสอบให้แน่ใจว่าดัชนีของเราได้รับการอัปเดตเพื่อให้สอดคล้องกับการเปลี่ยนแปลงข้อมูลของเรา โชคดีที่อัญมณี Chewy มาพร้อมกับประโยชน์ update_index
rspec การแข่งขัน:
describe EntertainmentIndex do # No need to cleanup Elasticsearch as requests are # stubbed in case of `update_index` matcher usage. describe 'Tag' do # We create several books with the same tag let(:books) { create_list :book, 2, tag_list: 'tag1' } specify do # We expect that after modifying the tag name... expect do ActsAsTaggableOn::Tag.where(name: 'tag1').update_attributes(name: 'tag2') # ... the corresponding type will be updated with previously-created books. end.to update_index('entertainment#book').and_reindex(books, with: {tags: ['tag2']}) end end end
ต่อไปเราต้องทดสอบว่าคำค้นหาจริงดำเนินการอย่างถูกต้องและส่งกลับผลลัพธ์ที่คาดหวัง:
describe EntertainmentSearch do # Just defining helpers for simplifying testing def search attributes = {} EntertainmentSearch.new(attributes).search end # Import helper as well def import *args # We are using `import!` here to be sure all the objects are imported # correctly before examples run. EntertainmentIndex.import! *args end # Deletes and recreates index before every example before { EntertainmentIndex.purge! } describe '#min_year, #max_year' do let(:book) { create(:book, year: 1925) } let(:movie) { create(:movie, year: 1970) } let(:cartoon) { create(:cartoon, year: 1995) } before { import book: book, movie: movie, cartoon: cartoon } # NOTE: The sample code below provides a clear usage example but is not # optimized code. Something along the following lines would perform better: # `specify { search(min_year: 1970).map(&:id).map(&:to_i) # .should =~ [movie, cartoon].map(&:id) }` specify { search(min_year: 1970).load.should =~ [movie, cartoon] } specify { search(max_year: 1980).load.should =~ [book, movie] } specify { search(min_year: 1970, max_year: 1980).load.should == [movie] } specify { search(min_year: 1980, max_year: 1970).should == [] } end end
ทดสอบการแก้ไขปัญหาคลัสเตอร์
สุดท้ายนี่คือคำแนะนำสำหรับการแก้ไขปัญหาคลัสเตอร์ทดสอบของคุณ:
-
ในการเริ่มต้นให้ใช้คลัสเตอร์หนึ่งโหนดในหน่วยความจำ มันจะเร็วกว่ามากสำหรับสเปก ในกรณีของเรา: TEST_CLUSTER_NODES=1 rake elasticsearch:start
-
มีปัญหาบางอย่างที่มีอยู่เกี่ยวกับ elasticsearch-extensions
การใช้งานคลัสเตอร์ทดสอบเองที่เกี่ยวข้องกับการตรวจสอบสถานะคลัสเตอร์แบบโหนดเดียว (ในบางกรณีจะเป็นสีเหลืองและจะไม่เป็นสีเขียวดังนั้นการตรวจสอบการเริ่มคลัสเตอร์สถานะสีเขียวจะล้มเหลวทุกครั้ง) ปัญหาได้รับการแก้ไขในทางแยก แต่หวังว่าจะได้รับการแก้ไขใน repo หลักเร็ว ๆ นี้
-
สำหรับชุดข้อมูลแต่ละชุดให้จัดกลุ่มคำขอของคุณตามข้อกำหนด (เช่นนำเข้าข้อมูลของคุณครั้งเดียวแล้วดำเนินการหลายคำขอ) Elasticsearch อุ่นเครื่องเป็นเวลานานและใช้หน่วยความจำฮีปจำนวนมากในขณะที่นำเข้าข้อมูลดังนั้นอย่าทำมากเกินไปโดยเฉพาะอย่างยิ่งหากคุณมีข้อกำหนดมากมาย
-
ตรวจสอบให้แน่ใจว่าเครื่องของคุณมีหน่วยความจำเพียงพอมิฉะนั้น Elasticsearch จะหยุดทำงาน (เราต้องการประมาณ 5GB สำหรับการทดสอบเครื่องเสมือนแต่ละเครื่องและประมาณ 1GB สำหรับ Elasticsearch เอง)
การเลิกราแก้วทำให้เกิดการล่มสลายได้อย่างไร
ห่อ
Elasticsearch อธิบายตัวเองว่าเป็น 'โอเพนซอร์สที่ยืดหยุ่นและทรงพลังการค้นหาแบบเรียลไทม์และเครื่องมือวิเคราะห์' เป็นมาตรฐานทองคำในเทคโนโลยีการค้นหา
ด้วย Chewy ของเรา นักพัฒนาราง ได้บรรจุสิทธิประโยชน์เหล่านี้ไว้ในรูปแบบการผลิตที่เรียบง่ายใช้งานง่ายคุณภาพการผลิตโอเพ่นซอร์ส Ruby gem ที่ให้การทำงานร่วมกับ Rails อย่างแน่นหนา Elasticsearch และ Rails - ช่างเป็นการผสมผสานที่ยอดเยี่ยม!
Elasticsearch และ Rails - ช่างเป็นการผสมผสานที่ยอดเยี่ยม! ทวีต
ภาคผนวก: Elasticsearch internalals
นี่คือไฟล์ มาก คำแนะนำสั้น ๆ เกี่ยวกับ Elasticsearch 'ภายใต้ประทุน' ...
Elasticsearch ถูกสร้างขึ้นบน ลูซีน ซึ่งใช้เอง ดัชนีกลับหัว เป็นโครงสร้างข้อมูลหลัก ตัวอย่างเช่นหากเรามีเชือก 'สุนัขกระโดดสูง' 'กระโดดข้ามรั้ว' และ 'รั้วสูงเกินไป' เราจะได้โครงสร้างต่อไปนี้:
'the' [0, 0], [1, 2], [2, 0] 'dogs' [0, 1] 'jump' [0, 2], [1, 0] 'high' [0, 3], [2, 4] 'over' [1, 1] 'fence' [1, 3], [2, 1] 'was' [2, 2] 'too' [2, 3]
ดังนั้นทุกคำจึงมีทั้งการอ้างอิงและตำแหน่งในข้อความ นอกจากนี้เราเลือกที่จะแก้ไขข้อกำหนดของเรา (เช่นโดยการลบคำหยุดเช่น 'the') และนำไปใช้ แฮชการออกเสียง ทุกเทอม (คุณเดาได้ไหม อัลกอริทึม ?):
'DAG' [0, 1] 'JANP' [0, 2], [1, 0] 'HAG' [0, 3], [2, 4] 'OVAR' [1, 1] 'FANC' [1, 3], [2, 1] 'W' [2, 2] 'T' [2, 3]
หากเราค้นหาคำว่า“ สุนัขกระโดด” จะมีการวิเคราะห์ในลักษณะเดียวกับข้อความต้นทางกลายเป็น“ DAG JANP” หลังการแฮช (“ สุนัข” มีแฮชเหมือนกับ“ สุนัข” เช่นเดียวกับ“ การกระโดด” และ 'กระโดด').
นอกจากนี้เรายังเพิ่มตรรกะบางอย่างระหว่างคำแต่ละคำในสตริง (ขึ้นอยู่กับการตั้งค่าการกำหนดค่า) โดยเลือกระหว่าง (“ DAG” และ“ JANP”) หรือ (“ DAG” หรือ“ JANP”) อดีตกลับจุดตัดของ [0] & [0, 1]
(เช่นเอกสาร 0) และหลัง [0] | [0, 1]
(เช่นเอกสาร 0 และ 1) ตำแหน่งในข้อความสามารถใช้สำหรับการให้คะแนนผลลัพธ์และแบบสอบถามที่ขึ้นกับตำแหน่ง