Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Làm thế nào để tìm các kết quả tương tự và sắp xếp theo độ tương tự?

Tôi đã phát hiện ra rằng khoảng cách Levenshtein có thể tốt khi bạn đang tìm kiếm một chuỗi đầy đủ so với một chuỗi đầy đủ khác, nhưng khi bạn đang tìm kiếm các từ khóa trong một chuỗi, phương pháp này không trả về (đôi khi) kết quả mong muốn. Hơn nữa, chức năng SOUNDEX không phù hợp với các ngôn ngữ khác ngoài tiếng Anh nên khá hạn chế. Bạn có thể bỏ qua LIKE, nhưng nó thực sự dành cho các tìm kiếm cơ bản. Bạn có thể muốn xem xét các phương pháp tìm kiếm khác cho những gì bạn muốn đạt được. Ví dụ:

Bạn có thể sử dụng Lucene làm cơ sở tìm kiếm cho các dự án của bạn. Nó được triển khai trong hầu hết các ngôn ngữ lập trình chính và nó sẽ khá nhanh và linh hoạt. Phương pháp này có lẽ là tốt nhất, vì nó không chỉ tìm kiếm các chuỗi con mà còn cả chuyển vị chữ cái, tiền tố và hậu tố (tất cả đều được kết hợp). Tuy nhiên, bạn cần giữ một chỉ mục riêng (sử dụng CRON để cập nhật nó từ một tập lệnh độc lập thỉnh thoảng vẫn hoạt động).

Hoặc, nếu bạn muốn một giải pháp MySQL, chức năng toàn văn bản là khá tốt và chắc chắn nhanh hơn một thủ tục được lưu trữ. Nếu các bảng của bạn không phải là MyISAM, bạn có thể tạo một bảng tạm thời, sau đó thực hiện tìm kiếm toàn văn bản của mình:

CREATE TABLE IF NOT EXISTS `tests`.`data_table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(2000) CHARACTER SET latin1 NOT NULL,
  `description` text CHARACTER SET latin1 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;

Sử dụng trình tạo dữ liệu để tạo một số dữ liệu ngẫu nhiên nếu bạn không muốn tự mình tạo ra nó ...

** LƯU Ý **:loại cột phải là latin1_bin để thực hiện tìm kiếm phân biệt chữ hoa chữ thường thay vì phân biệt chữ hoa chữ thường với latin1 . Đối với chuỗi unicode, tôi khuyên bạn nên sử dụng utf8_bin phân biệt chữ hoa chữ thường và utf8_general_ci cho các tìm kiếm không phân biệt chữ hoa chữ thường.

DROP TABLE IF EXISTS `tests`.`data_table_temp`;
CREATE TEMPORARY TABLE `tests`.`data_table_temp`
   SELECT * FROM `tests`.`data_table`;

ALTER TABLE `tests`.`data_table_temp`  ENGINE = MYISAM;

ALTER TABLE `tests`.`data_table_temp` ADD FULLTEXT `FTK_title_description` (
  `title` ,
  `description`
);

SELECT *,
       MATCH (`title`,`description`)
       AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE) as `score`
  FROM `tests`.`data_table_temp`
 WHERE MATCH (`title`,`description`)
       AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE)
 ORDER BY `score` DESC;

DROP TABLE `tests`.`data_table_temp`;

Đọc thêm về nó từ trang tham chiếu MySQL API

Nhược điểm của điều này là nó sẽ không tìm kiếm chuyển vị chữ cái hoặc các từ "tương tự, nghe giống như".

** CẬP NHẬT **

Sử dụng Lucene cho tìm kiếm của bạn, bạn sẽ chỉ cần tạo một công việc cron (tất cả các máy chủ web đều có "tính năng" này) trong đó công việc này sẽ chỉ thực thi một tập lệnh PHP (ví dụ:"cd / path / to / script; php searchindexer.php" ) sẽ cập nhật các chỉ mục. Lý do là việc lập chỉ mục hàng nghìn "tài liệu" (hàng, dữ liệu, v.v.) có thể mất vài giây, thậm chí vài phút, nhưng điều này là để đảm bảo rằng tất cả các tìm kiếm được thực hiện nhanh nhất có thể. Do đó, bạn có thể muốn tạo một công việc trì hoãn để máy chủ chạy. Có thể là qua đêm, hoặc trong giờ tới, điều này tùy thuộc vào bạn. Tập lệnh PHP sẽ trông giống như sau:

$indexer = Zend_Search_Lucene::create('/path/to/lucene/data');

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
  // change this option for your need
  new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);

$rowSet = getDataRowSet();  // perform your SQL query to fetch whatever you need to index
foreach ($rowSet as $row) {
   $doc = new Zend_Search_Lucene_Document();
   $doc->addField(Zend_Search_Lucene_Field::text('field1', $row->field1, 'utf-8'))
       ->addField(Zend_Search_Lucene_Field::text('field2', $row->field2, 'utf-8'))
       ->addField(Zend_Search_Lucene_Field::unIndexed('someValue', $someVariable))
       ->addField(Zend_Search_Lucene_Field::unIndexed('someObj', serialize($obj), 'utf-8'))
  ;
  $indexer->addDocument($doc);
}

// ... you can get as many $rowSet as you want and create as many documents
// as you wish... each document doesn't necessarily need the same fields...
// Lucene is pretty flexible on this

$indexer->optimize();  // do this every time you add more data to you indexer...
$indexer->commit();    // finalize the process

Sau đó, về cơ bản đây là cách bạn tìm kiếm (tìm kiếm cơ bản):

$index = Zend_Search_Lucene::open('/path/to/lucene/data');

// same search options
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
   new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);

Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8');

$query = 'php +field1:foo';  // search for the word 'php' in any field,
                                 // +search for 'foo' in field 'field1'

$hits = $index->find($query);

$numHits = count($hits);
foreach ($hits as $hit) {
   $score = $hit->score;  // the hit weight
   $field1 = $hit->field1;
   // etc.
}

Dưới đây là các trang web tuyệt vời về Lucene trong Java , PHP .Net .

Kết luận mỗi phương pháp tìm kiếm có ưu và nhược điểm riêng:

  • Bạn đã đề cập đến Tìm kiếm nhân sư và nó trông rất ổn, miễn là bạn có thể làm cho quá trình ngừng hoạt động trên máy chủ lưu trữ web của mình.
  • Zend Lucene yêu cầu một công việc cron để lập chỉ mục lại cơ sở dữ liệu. Mặc dù nó khá minh bạch với người dùng, nhưng điều này có nghĩa là mọi dữ liệu mới (hoặc dữ liệu đã xóa!) Không phải lúc nào cũng đồng bộ với dữ liệu trong cơ sở dữ liệu của bạn và do đó sẽ không hiển thị ngay khi người dùng tìm kiếm.
  • Tìm kiếm FULLTEXT trong MySQL rất tốt và nhanh chóng, nhưng sẽ không cung cấp cho bạn tất cả sức mạnh và tính linh hoạt của hai cách đầu tiên.

Vui lòng bình luận nếu tôi có quên / bỏ sót điều gì.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thực hiện tìm kiếm Nhạy cảm trong MySql

  2. Làm thế nào để thực hiện chèn hàng loạt trong MySQL?

  3. Làm thế nào để đồng bộ cơ sở dữ liệu SQLite trên điện thoại Android với cơ sở dữ liệu MySQL trên máy chủ?

  4. Chuyển đổi giản đồ MySQL sang Github Wiki?

  5. PDO fetch:Nhóm tất cả các cặp khóa-giá trị vào mảng assoc