SearchCop ขยายโมเดล ActiveRecord ของคุณเพื่อรองรับเครื่องมือค้นหาข้อความแบบเต็ม เช่น ข้อความค้นหาผ่านสตริงข้อความค้นหาแบบธรรมดาและข้อความค้นหาแบบแฮช สมมติว่าคุณมีโมเดล Book
ที่มีคุณสมบัติต่างๆ เช่น title
author
stock
price
available
การใช้ SearchCop คุณสามารถดำเนินการ:
Book . search ( "Joanne Rowling Harry Potter" )
Book . search ( "author: Rowling title:'Harry Potter'" )
Book . search ( "price > 10 AND price < 20 -stock:0 (Potter OR Rowling)" )
# ...
ดังนั้น คุณสามารถแจกสตริงคำค้นหาให้กับโมเดลของคุณและคุณ ผู้ดูแลระบบแอปและ/หรือผู้ใช้จะได้รับฟีเจอร์การสืบค้นที่มีประสิทธิภาพโดยไม่จำเป็นต้องรวมเซิร์ฟเวอร์การค้นหาของบุคคลที่สามเพิ่มเติม เนื่องจาก SearchCop สามารถใช้ความสามารถดัชนีข้อความแบบเต็มของ RDBMS ของคุณได้ วิธีไม่เชื่อเรื่องฐานข้อมูล (ปัจจุบันรองรับดัชนีข้อความแบบเต็มของ MySQL และ PostgreSQL) และปรับแบบสอบถามให้เหมาะสมเพื่อใช้ประโยชน์สูงสุด อ่านเพิ่มเติมด้านล่าง
รองรับการสืบค้นแบบแฮชที่ซับซ้อนเช่นกัน:
Book . search ( author : "Rowling" , title : "Harry Potter" )
Book . search ( or : [ { author : "Rowling" } , { author : "Tolkien" } ] )
Book . search ( and : [ { price : { gt : 10 } } , { not : { stock : 0 } } , or : [ { title : "Potter" } , { author : "Rowling" } ] ] )
Book . search ( or : [ { query : "Rowling -Potter" } , { query : "Tolkien -Rings" } ] )
Book . search ( title : { my_custom_sql_query : "Rowl" } } )
# ...
เพิ่มบรรทัดนี้ลงใน Gemfile ของแอปพลิเคชันของคุณ:
gem 'search_cop'
แล้วดำเนินการ:
$ bundle
หรือติดตั้งด้วยตัวเองเป็น:
$ gem install search_cop
หากต้องการเปิดใช้งาน SearchCop สำหรับโมเดล include SearchCop
และระบุแอตทริบิวต์ที่คุณต้องการเปิดเผยต่อคำค้นหาภายใน search_scope
:
class Book < ActiveRecord :: Base
include SearchCop
search_scope :search do
attributes :title , :description , :stock , :price , :created_at , :available
attributes comment : [ "comments.title" , "comments.message" ]
attributes author : "author.name"
# ...
end
has_many :comments
belongs_to :author
end
แน่นอนคุณสามารถระบุบล็อก search_scope
หลายบล็อกได้ตามที่คุณต้องการ:
search_scope :admin_search do
attributes :title , :description , :stock , :price , :created_at , :available
# ...
end
search_scope :user_search do
attributes :title , :description
# ...
end
SearchCop แยกวิเคราะห์แบบสอบถามและแมปกับ SQL Query ด้วยวิธีไม่เชื่อเรื่องฐานข้อมูล ดังนั้น SearchCop จึงไม่ผูกกับ RDBMS ใดโดยเฉพาะ
Book . search ( "stock > 0" )
# ... WHERE books.stock > 0
Book . search ( "price > 10 stock > 0" )
# ... WHERE books.price > 10 AND books.stock > 0
Book . search ( "Harry Potter" )
# ... WHERE (books.title LIKE '%Harry%' OR books.description LIKE '%Harry%' OR ...) AND (books.title LIKE '%Potter%' OR books.description LIKE '%Potter%' ...)
Book . search ( "available:yes OR created_at:2014" )
# ... WHERE books.available = 1 OR (books.created_at >= '2014-01-01 00:00:00.00000' and books.created_at <= '2014-12-31 23:59:59.99999')
SearchCop กำลังใช้เมธอด beginning_of_year และ end_of_year ของ ActiveSupport สำหรับค่าที่ใช้ในการสร้างแบบสอบถาม SQL สำหรับในกรณีนี้
แน่นอนว่าข้อความค้นหา LIKE '%...%'
เหล่านี้จะไม่ได้รับประสิทธิภาพสูงสุด แต่โปรดตรวจสอบส่วนด้านล่างเกี่ยวกับความสามารถด้านข้อความแบบเต็มของ SearchCop เพื่อทำความเข้าใจว่าข้อความค้นหาผลลัพธ์จะสามารถปรับให้เหมาะสมได้อย่างไร
เนื่องจาก Book.search(...)
ส่งคืน ActiveRecord::Relation
คุณมีอิสระในการประมวลผลผลการค้นหาล่วงหน้าหรือหลังในทุกวิถีทางที่เป็นไปได้:
Book . where ( available : true ) . search ( "Harry Potter" ) . order ( "books.id desc" ) . paginate ( page : params [ :page ] )
เมื่อคุณส่งสตริงการสืบค้นไปยัง SearchCop มันจะถูกแยกวิเคราะห์ วิเคราะห์ และแมปเพื่อสร้างการสืบค้น SQL ในที่สุด เพื่อให้แม่นยำยิ่งขึ้น เมื่อ SearchCop แยกวิเคราะห์แบบสอบถาม มันจะสร้างวัตถุ (โหนด) ซึ่งแสดงถึงนิพจน์แบบสอบถาม (And-, Or-, Not-, String-, Date-, ฯลฯ โหนด) ในการสร้างแบบสอบถาม SQL นั้น SearchCop ใช้แนวคิดของผู้เยี่ยมชม เช่น ที่ใช้ใน Arel ดังนั้น สำหรับทุกโหนดจะต้องมีผู้เยี่ยมชม ซึ่งจะแปลงโหนดเป็น SQL เมื่อไม่มีผู้เยี่ยมชม ข้อยกเว้นจะเกิดขึ้นเมื่อตัวสร้างแบบสอบถามพยายาม "เยี่ยมชม" โหนด ผู้เยี่ยมชมมีหน้าที่รับผิดชอบในการฆ่าเชื้ออินพุตที่ผู้ใช้ให้มา โดยทั่วไปจะทำผ่านเครื่องหมายคำพูด (string-, table-name-, column-quoting ฯลฯ) SearchCop กำลังใช้วิธีการที่ได้รับจากอะแดปเตอร์การเชื่อมต่อ ActiveRecord สำหรับการฆ่าเชื้อ/การเสนอราคาเพื่อป้องกันการแทรก SQL แม้ว่าเราจะไม่สามารถปลอดภัยจากปัญหาด้านความปลอดภัยได้ 100% แต่ SearchCop ให้ความสำคัญกับปัญหาด้านความปลอดภัยอย่างจริงจัง โปรดรายงานอย่างรับผิดชอบผ่านการรักษาความปลอดภัยที่ flakks dot com ในกรณีที่คุณพบปัญหาที่เกี่ยวข้องกับความปลอดภัย
SearchCop รองรับฟิลด์ json สำหรับ MySQL เช่นเดียวกับฟิลด์ json, jsonb และ hstore สำหรับ postgres ในปัจจุบัน ค่าของฟิลด์ควรเป็นสตริงเสมอและไม่รองรับอาร์เรย์ คุณสามารถระบุแอตทริบิวต์ json ได้ผ่านทาง:
search_scope :search do
attributes user_agent : "context->browser->user_agent"
# ...
end
โดยที่ context
คือคอลัมน์ json/jsonb ซึ่งประกอบด้วย:
{
"browser" : {
"user_agent" : " Firefox ... "
}
}
ตามค่าเริ่มต้น เช่น หากคุณไม่บอก SearchCop เกี่ยวกับดัชนีข้อความแบบเต็มของคุณ SearchCop จะใช้คำสั่ง LIKE '%...%'
ขออภัย เว้นแต่คุณจะสร้างดัชนีไตรแกรม (postgres เท่านั้น) ข้อความค้นหาเหล่านี้ไม่สามารถใช้ดัชนี SQL ได้ ดังนั้น RDBMS ของคุณจึงต้องสแกนทุกแถวเมื่อคุณค้นหา Book.search("Harry Potter")
หรือที่คล้ายกัน เพื่อหลีกเลี่ยงการลงโทษการสืบค้น LIKE
SearchCop สามารถใช้ประโยชน์จากความสามารถในการจัดทำดัชนีข้อความแบบเต็มของ MySQL และ PostgreSQL หากต้องการใช้ดัชนีแบบเต็มที่มีอยู่แล้ว เพียงบอกให้ SearchCop ใช้ดัชนีเหล่านี้ผ่าน:
class Book < ActiveRecord :: Base
# ...
search_scope :search do
attributes :title , :author
options :title , :type => :fulltext
options :author , :type => :fulltext
end
# ...
end
SearchCop จะเปลี่ยนแบบสอบถาม SQL สำหรับแอตทริบิวต์ที่มีดัชนีข้อความแบบเต็มอย่างโปร่งใสเป็น:
Book . search ( "Harry Potter" )
# MySQL: ... WHERE (MATCH(books.title) AGAINST('+Harry' IN BOOLEAN MODE) OR MATCH(books.author) AGAINST('+Harry' IN BOOLEAN MODE)) AND (MATCH(books.title) AGAINST ('+Potter' IN BOOLEAN MODE) OR MATCH(books.author) AGAINST('+Potter' IN BOOLEAN MODE))
# PostgreSQL: ... WHERE (to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Harry') OR to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Harry')) AND (to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Potter') OR to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Potter'))
แน่นอนว่าข้อความค้นหาเหล่านี้ไม่ได้ส่งคืนผลลัพธ์เหมือนกับข้อความค้นหา LIKE
แบบไวด์การ์ดเสมอไป เนื่องจากเราค้นหาคำแทนที่จะเป็นสตริงย่อย อย่างไรก็ตาม ดัชนีแบบเต็มมักจะให้ประสิทธิภาพที่ดีกว่าแน่นอน
นอกจากนี้ ข้อความค้นหาข้างต้นยังไม่สมบูรณ์แบบ เพื่อปรับปรุงให้ดียิ่งขึ้น SearchCop พยายามปรับแบบสอบถามให้เหมาะสมเพื่อใช้ดัชนีข้อความแบบเต็มให้เกิดประโยชน์สูงสุดในขณะที่ยังคงอนุญาตให้ผสมกับแอตทริบิวต์ที่ไม่ใช่ข้อความเต็มได้ เพื่อปรับปรุงการสืบค้นให้ดียิ่งขึ้น คุณสามารถจัดกลุ่มแอตทริบิวต์และระบุฟิลด์เริ่มต้นที่จะค้นหาได้ โดยที่ SearchCop จะต้องไม่ค้นหาภายในทุกฟิลด์อีกต่อไป:
search_scope :search do
attributes all : [ :author , :title ]
options :all , :type => :fulltext , default : true
# Use default: true to explicitly enable fields as default fields (whitelist approach)
# Use default: false to explicitly disable fields as default fields (blacklist approach)
end
ตอนนี้ SearchCop สามารถเพิ่มประสิทธิภาพการค้นหาต่อไปนี้ แต่ยังไม่เหมาะสมที่สุด:
Book . search ( "Rowling OR Tolkien stock > 1" )
# MySQL: ... WHERE ((MATCH(books.author) AGAINST('+Rowling' IN BOOLEAN MODE) OR MATCH(books.title) AGAINST('+Rowling' IN BOOLEAN MODE)) OR (MATCH(books.author) AGAINST('+Tolkien' IN BOOLEAN MODE) OR MATCH(books.title) AGAINST('+Tolkien' IN BOOLEAN MODE))) AND books.stock > 1
# PostgreSQL: ... WHERE ((to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Rowling') OR to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Rowling')) OR (to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Tolkien') OR to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Tolkien'))) AND books.stock > 1
ต่อไปนี้คือแบบสอบถามที่มีประสิทธิภาพมากขึ้น:
Book . search ( "Rowling OR Tolkien stock > 1" )
# MySQL: ... WHERE MATCH(books.author, books.title) AGAINST('Rowling Tolkien' IN BOOLEAN MODE) AND books.stock > 1
# PostgreSQL: ... WHERE to_tsvector('simple', books.author || ' ' || books.title) @@ to_tsquery('simple', 'Rowling | Tokien') and books.stock > 1
เกิดอะไรขึ้นที่นี่? เราระบุ all
เป็นชื่อของกลุ่มแอ็ตทริบิวต์ที่ประกอบด้วย author
และ title
นอกจากนี้ ขณะที่เราระบุ all
ให้เป็นแอตทริบิวต์ข้อความแบบเต็ม SearchCop จะถือว่ามีดัชนีข้อความแบบเต็มปรากฏอยู่ใน author
และ title
เพื่อให้แบบสอบถามได้รับการปรับให้เหมาะสมตามนั้น สุดท้าย เราได้ระบุ all
ให้เป็นแอตทริบิวต์เริ่มต้นในการค้นหา โดยที่ SearchCop สามารถละเว้นคุณลักษณะอื่นๆ เช่น stock
ตราบใดที่ไม่ได้ระบุไว้ในข้อความค้นหาโดยตรง (เช่น สำหรับ stock > 0
)
การสืบค้นอื่นๆ จะได้รับการปรับให้เหมาะสมในลักษณะเดียวกัน โดยที่ SearchCop จะพยายามลดข้อจำกัดของข้อความทั้งหมดให้เหลือน้อยที่สุดภายในการสืบค้น นั่นคือ MATCH() AGAINST()
สำหรับ MySQL และ to_tsvector() @@ to_tsquery()
สำหรับ PostgreSQL
Book . search ( "(Rowling -Potter) OR Tolkien" )
# MySQL: ... WHERE MATCH(books.author, books.title) AGAINST('(+Rowling -Potter) Tolkien' IN BOOLEAN MODE)
# PostgreSQL: ... WHERE to_tsvector('simple', books.author || ' ' || books.title) @@ to_tsquery('simple', '(Rowling & !Potter) | Tolkien')
หากต้องการสร้างดัชนีแบบเต็มบน books.title
ใน MySQL เพียงใช้:
add_index :books , :title , :type => :fulltext
เกี่ยวกับดัชนีผสม ซึ่งจะใช้สำหรับฟิลด์เริ่มต้น all
ที่เราระบุไว้ข้างต้น ให้ใช้:
add_index :books , [ :author , :title ] , :type => :fulltext
โปรดทราบว่า MySQL รองรับดัชนีข้อความแบบเต็มสำหรับ MyISAM และสำหรับ MySQL เวอร์ชัน 5.6+ สำหรับ InnoDB เช่นกัน สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับดัชนีฟูลเท็กซ์ MySQL โปรดไปที่http://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
เกี่ยวกับ PostgreSQL มีวิธีอื่นๆ มากมายในการสร้างดัชนีข้อความแบบเต็ม อย่างไรก็ตาม วิธีที่ง่ายที่สุดวิธีหนึ่งคือ:
ActiveRecord :: Base . connection . execute "CREATE INDEX fulltext_index_books_on_title ON books USING GIN(to_tsvector('simple', title))"
นอกจากนี้ สำหรับ PostgreSQL คุณควรเปลี่ยนรูปแบบสคีมาใน config/application.rb
:
config . active_record . schema_format = :sql
เกี่ยวกับดัชนีผสมสำหรับ PostgreSQL ให้ใช้:
ActiveRecord :: Base . connection . execute "CREATE INDEX fulltext_index_books_on_title ON books USING GIN(to_tsvector('simple', author || ' ' || title))"
ในการจัดการค่า NULL ด้วย PostgreSQL อย่างถูกต้อง ให้ใช้ COALESCE ทั้งในเวลาสร้างดัชนีและเมื่อระบุ search_scope
:
ActiveRecord :: Base . connection . execute "CREATE INDEX fulltext_index_books_on_title ON books USING GIN(to_tsvector('simple', COALESCE(author, '') || ' ' || COALESCE(title, '')))"
บวก:
search_scope :search do
attributes :title
options :title , :type => :fulltext , coalesce : true
end
หากต้องการใช้พจนานุกรม PostgreSQL อื่นนอกเหนือจาก simple
คุณต้องสร้างดัชนีตามนั้นและคุณต้องบอก SearchCop เกี่ยวกับเรื่องนี้ เช่น:
search_scope :search do
attributes :title
options :title , :type => :fulltext , dictionary : "english"
end
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับดัชนีข้อความแบบเต็มของ PostgreSQL โปรดไปที่ http://www.postgresql.org/docs/9.3/static/textsearch.html
ในกรณีที่คุณแสดงแอตทริบิวต์ที่ไม่ใช่ข้อความเต็มสำหรับคำค้นหา (ราคา หุ้น ฯลฯ) ข้อความค้นหาที่เกี่ยวข้อง เช่น Book.search("stock > 0")
จะได้กำไรจากดัชนีที่ไม่ใช่ข้อความเต็มตามปกติ ดังนั้น คุณควรเพิ่มดัชนีปกติในทุกคอลัมน์ที่คุณแสดงให้กับคำค้นหา บวกกับดัชนีข้อความแบบเต็มสำหรับแอตทริบิวต์ข้อความแบบเต็มทุกรายการ
ในกรณีที่คุณไม่สามารถใช้ดัชนีฟูลเท็กซ์ได้ เนื่องจากคุณยังใช้ MySQL 5.5 ในขณะที่ใช้ InnoDB หรือ RDBMS อื่นโดยไม่มีการสนับสนุนฟูลเท็กซ์ คุณสามารถทำให้ RDBMS ของคุณใช้ดัชนีที่ไม่ใช่ฟูลเท็กซ์ตามปกติสำหรับคอลัมน์สตริงได้ หากคุณไม่ต้องการ ทิ้งไวด์การ์ดไว้ในข้อความค้นหา LIKE
เพียงระบุตัวเลือกต่อไปนี้:
class User < ActiveRecord :: Base
include SearchCop
search_scope :search do
attributes :username
options :username , left_wildcard : false
end
# ...
โดยที่ SearchCop จะละเว้นไวด์การ์ดด้านซ้ายสุด
User . search ( "admin" )
# ... WHERE users.username LIKE 'admin%'
ในทำนองเดียวกัน คุณสามารถปิดการใช้งานไวด์การ์ดที่ถูกต้องได้เช่นกัน:
search_scope :search do
attributes :username
options :username , right_wildcard : false
end
เมื่อคุณกำหนดหลายฟิลด์ในขอบเขตการค้นหา SearcCop จะใช้ตัวดำเนินการ AND เป็นค่าเริ่มต้นเพื่อเชื่อมเงื่อนไข เช่น:
class User < ActiveRecord :: Base
include SearchCop
search_scope :search do
attributes :username , :fullname
end
# ...
end
ดังนั้นการค้นหาเช่น User.search("something")
จะสร้างข้อความค้นหาโดยมีเงื่อนไขดังต่อไปนี้:
... WHERE username LIKE ' %something% ' AND fullname LIKE ' %something% '
อย่างไรก็ตาม มีบางกรณีที่ไม่ต้องการใช้ AND เป็นตัวดำเนินการเริ่มต้น ดังนั้น SearchCop จึงอนุญาตให้คุณแทนที่และใช้ OR เป็นตัวดำเนินการเริ่มต้นแทน แบบสอบถามเช่น User.search("something", default_operator: :or)
จะสร้างแบบสอบถามโดยใช้ OR เพื่อเชื่อมเงื่อนไข
... WHERE username LIKE ' %something% ' OR fullname LIKE ' %something% '
สุดท้ายนี้ โปรดทราบว่าคุณสามารถใช้กับดัชนี/ข้อความค้นหาแบบเต็มได้เช่นกัน
หากคุณระบุคุณลักษณะที่ค้นหาได้จากโมเดลอื่น เช่น
class Book < ActiveRecord :: Base
# ...
belongs_to :author
search_scope :search do
attributes author : "author.name"
end
# ...
end
SearchCop จะกระตือรือร้นที่ eager_load
การเชื่อมโยงที่อ้างอิงตามค่าเริ่มต้นเมื่อคุณดำเนินการ Book.search(...)
หากคุณไม่ต้องการ eager_load
อัตโนมัติหรือจำเป็นต้องดำเนินการพิเศษ ให้ระบุ scope
:
class Book < ActiveRecord :: Base
# ...
search_scope :search do
# ...
scope { joins ( :author ) . eager_load ( :comments ) } # etc.
end
# ...
end
จากนั้น SearchCop จะข้ามการโหลดการเชื่อมโยงอัตโนมัติและจะใช้ขอบเขตแทน คุณสามารถใช้ scope
ร่วมกับ aliases
เพื่อดำเนินการรวมที่ซับซ้อนโดยพลการและค้นหาในโมเดล/ตารางที่รวมเข้าด้วยกัน:
class Book < ActiveRecord :: Base
# ...
search_scope :search do
attributes similar : [ "similar_books.title" , "similar_books.description" ]
scope do
joins "left outer join books similar_books on ..."
end
aliases similar_books : Book # Tell SearchCop how to map SQL aliases to models
end
# ...
end
สมาคมต่างๆ สามารถอ้างอิงและใช้ได้เช่นกัน:
class Book < ActiveRecord :: Base
# ...
has_many :comments
has_many :users , :through => :comments
search_scope :search do
attributes user : "users.username"
end
# ...
end
SearchCop พยายามอนุมานชื่อคลาสของโมเดลและนามแฝง SQL จากแอตทริบิวต์ที่ระบุเพื่อตรวจหาคำจำกัดความประเภทข้อมูลโดยอัตโนมัติ ฯลฯ ซึ่งมักจะใช้งานได้ค่อนข้างดี ในกรณีที่คุณใช้ชื่อตารางที่กำหนดเองผ่าน self.table_name = ...
หรือหากโมเดลเชื่อมโยงกันหลายครั้ง SearchCop จะไม่สามารถอนุมานชื่อคลาสและชื่อแทน SQL ได้ เช่น
class Book < ActiveRecord :: Base
# ...
has_many :users , :through => :comments
belongs_to :user
search_scope :search do
attributes user : [ "user.username" , "users_books.username" ]
end
# ...
end
ที่นี่ เพื่อให้การสืบค้นทำงานได้ คุณต้องใช้ users_books.username
เนื่องจาก ActiveRecord จะกำหนดนามแฝง SQL ที่แตกต่างกันให้กับผู้ใช้ภายในการสืบค้น SQL เนื่องจากโมเดลผู้ใช้เชื่อมโยงกันหลายครั้ง อย่างไรก็ตาม เนื่องจากตอนนี้ SearchCop ไม่สามารถอนุมานโมเดล User
จาก users_books
ได้ คุณต้องเพิ่ม:
class Book < ActiveRecord :: Base
# ...
search_scope :search do
# ...
aliases :users_books => :users
end
# ...
end
เพื่อบอก SearchCop เกี่ยวกับนามแฝงและการแมป SQL ที่กำหนดเอง นอกจากนี้ คุณสามารถรวมตัวเองได้ตลอดเวลาผ่าน scope {}
บวก aliases
และใช้นามแฝง sql ที่คุณกำหนดเองเพื่อให้เป็นอิสระจากชื่อที่กำหนดอัตโนมัติโดย ActiveRecord
สตริงการสืบค้น รองรับ AND/and
, OR/or
, :
, =
, !=
, <
, <=
, >
, >=
, NOT/not/-
, ()
, "..."
และ '...'
โอเปอเรเตอร์เริ่มต้นคือ AND
และ matches
, OR
มีความสำคัญมากกว่า AND
NOT
สามารถใช้เป็นตัวดำเนินการ infix เกี่ยวกับแอตทริบิวต์เดียวเท่านั้น
การสืบค้นแบบแฮชรองรับ and: [...]
และ or: [...]
ซึ่งรับอาร์เรย์ของ not: {...}
, matches: {...}
, eq: {...}
, not_eq: {...}
, lt: {...}
, lteq: {...}
, gt: {...}
, gteq: {...}
และ query: "..."
นอกจากนี้ query: "..."
ทำให้สามารถสร้างแบบสอบถามย่อยได้ กฎอื่นๆ สำหรับการสืบค้นสตริงการสืบค้นใช้กับการสืบค้นแบบแฮชเช่นกัน
SearchCop ยังจัดเตรียมความสามารถในการกำหนดตัวดำเนินการแบบกำหนดเองโดยการกำหนด generator
ใน search_scope
จากนั้นสามารถใช้กับการค้นหาข้อความค้นหาแบบแฮชได้ สิ่งนี้มีประโยชน์เมื่อคุณต้องการใช้ตัวดำเนินการฐานข้อมูลที่ SearchCop ไม่รองรับ
โปรดทราบว่าเมื่อใช้เครื่องกำเนิดไฟฟ้า คุณจะต้องรับผิดชอบในการฆ่าเชื้อ/เสนอราคา (ดูตัวอย่างด้านล่าง) มิฉะนั้นตัวสร้างของคุณจะอนุญาตให้ฉีด SQL ได้ ดังนั้น โปรดใช้เครื่องกำเนิดไฟฟ้าเฉพาะเมื่อคุณรู้ว่าคุณกำลังทำอะไรอยู่
ตัวอย่างเช่น หากคุณต้องการดำเนินการค้นหา LIKE
โดยที่ชื่อหนังสือขึ้นต้นด้วยสตริง คุณสามารถกำหนดขอบเขตการค้นหาได้ดังนี้:
search_scope :search do
attributes :title
generator :starts_with do | column_name , raw_value |
pattern = " #{ raw_value } %"
" #{ column_name } LIKE #{ quote pattern } "
end
end
เมื่อคุณต้องการดำเนินการค้นหา คุณใช้สิ่งนี้ดังนี้:
Book . search ( title : { starts_with : "The Great" } )
หมายเหตุด้านความปลอดภัย: แบบสอบถามที่ส่งคืนจากตัวสร้างจะถูกแก้ไขโดยตรงในแบบสอบถามที่ไปที่ฐานข้อมูลของคุณ นี่เป็นการเปิดจุดการฉีด SQL ที่อาจเกิดขึ้นในแอปของคุณ หากคุณใช้คุณลักษณะนี้ คุณจะต้องแน่ใจว่าแบบสอบถามที่คุณส่งคืนนั้นปลอดภัยในการดำเนินการ
เมื่อค้นหาในช่องบูลีน วันที่เวลา การประทับเวลา ฯลฯ SearchCop จะดำเนินการแมปบางอย่าง แบบสอบถามต่อไปนี้เทียบเท่า:
Book . search ( "available:true" )
Book . search ( "available:1" )
Book . search ( "available:yes" )
เช่นเดียวกับ
Book . search ( "available:false" )
Book . search ( "available:0" )
Book . search ( "available:no" )
สำหรับช่อง datetime และ timestamp SearchCop จะขยายค่าบางอย่างเป็นช่วง:
Book . search ( "created_at:2014" )
# ... WHERE created_at >= '2014-01-01 00:00:00' AND created_at <= '2014-12-31 23:59:59'
Book . search ( "created_at:2014-06" )
# ... WHERE created_at >= '2014-06-01 00:00:00' AND created_at <= '2014-06-30 23:59:59'
Book . search ( "created_at:2014-06-15" )
# ... WHERE created_at >= '2014-06-15 00:00:00' AND created_at <= '2014-06-15 23:59:59'
สามารถเชื่อมโยงการค้นหาได้ อย่างไรก็ตาม การเชื่อมโยงในปัจจุบันไม่อนุญาตให้ SearchCop ปรับการค้นหาแต่ละรายการให้เหมาะสมสำหรับดัชนีข้อความแบบเต็ม
Book . search ( "Harry" ) . search ( "Potter" )
จะสร้าง
# MySQL: ... WHERE MATCH(...) AGAINST('+Harry' IN BOOLEAN MODE) AND MATCH(...) AGAINST('+Potter' IN BOOLEAN MODE)
# PostgreSQL: ... WHERE to_tsvector(...) @@ to_tsquery('simple', 'Harry') AND to_tsvector(...) @@ to_tsquery('simple', 'Potter')
แทน
# MySQL: ... WHERE MATCH(...) AGAINST('+Harry +Potter' IN BOOLEAN MODE)
# PostgreSQL: ... WHERE to_tsvector(...) @@ to_tsquery('simple', 'Harry & Potter')
ดังนั้น หากคุณใช้ดัชนีแบบเต็ม คุณควรหลีกเลี่ยงการผูกมัด
เมื่อใช้ Model#search
SearchCop จะป้องกันไม่ให้มีข้อยกเว้นบางประการเกิดขึ้นในกรณีที่สตริงการสืบค้นที่ส่งไปนั้นไม่ถูกต้อง (ข้อผิดพลาดในการแยกวิเคราะห์ ข้อผิดพลาดประเภทข้อมูลที่เข้ากันไม่ได้ ฯลฯ) แต่ Model#search
จะส่งคืนความสัมพันธ์ที่ว่างเปล่าแทน อย่างไรก็ตาม หากคุณต้องการแก้ไขข้อบกพร่องบางกรณี ให้ใช้ Model#unsafe_search
ซึ่งจะทำให้เกิดข้อผิดพลาดขึ้น
Book . unsafe_search ( "stock: None" ) # => raise SearchCop::IncompatibleDatatype
SearchCop มีวิธีการสะท้อน ได้แก่ #attributes
, #default_attributes
, #options
และ #aliases
คุณสามารถใช้วิธีการเหล่านี้ เช่น จัดเตรียมวิดเจ็ตความช่วยเหลือในการค้นหาสำหรับโมเดลของคุณ ซึ่งแสดงรายการคุณลักษณะที่จะค้นหา รวมถึงแอตทริบิวต์เริ่มต้น เป็นต้น
class Product < ActiveRecord :: Base
include SearchCop
search_scope :search do
attributes :title , :description
options :title , default : true
end
end
Product . search_reflection ( :search ) . attributes
# {"title" => ["products.title"], "description" => ["products.description"]}
Product . search_reflection ( :search ) . default_attributes
# {"title" => ["products.title"]}
# ...
ตั้งแต่เวอร์ชัน 1.0.0 เป็นต้นไป SearchCop ใช้ Semantic Versioning: SemVer
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)