2 farklı tablo verilerini arama uygulamak nasıl?

7 Cevap php

MySQL ve PHP Kullanımı

Zaten hükümleri KARŞI MAÇ kullanıyorum.

Bu ayrı masalarda karşı iyi çalışıyor. I gibi mağazalar tabloda aramak istiyorsanız. Problem yok.

Ne istediğim bir tek sonuç sayfasında farklı tablolardan arama sonuçları ve görüntülemek mümkün olmaktır.

Örneğin ben "çikolata giysi" yazarsanız

aşağıdaki gibi ben 4 sonuçlar alabilirsiniz:

Shop1 sonuç

ShopItem1 sonuç

ShopItem2 sonuç

Shop2 sonuç

ve tabii en alakalı sonuçları ilk sırada olmalıdır.

ben oldukça bir kaç soru var. bilge yanı sıra uygulama bilge tasarım

1) benim tasarımını değiştirmek gerekir? i hem DÜKKAN ve shopproducts tablodan veri içeren ayrı bir tablo olarak adlandırılan arama sonuçlarını sahip düşünüyorum. ancak bu, bazı veri çoğaltma var demektir.

2) benim geçerli tasarım tutmak gerekir? eğer öyleyse, o zaman arama sonuçları 2 farklı tablolar arasında alaka olanlar yeryüzünde ne alabilirim?

rottentomatoes farklı gruplar kendi arama sonuçlarını organize olduğunu gördüm. Ancak, biz UI akıllıca gidin daha zor olacak belleği var, özellikle farklı tipleri ile sınırlı olmamak arama sonuçlarını tercih ederim.

http://www.rottentomatoes.com/search/full%5Fsearch.php?search=girl

YA aslında en iyi yolu nedir?

Ben birden çok tablo gibi görünüyor ne arama sonuçları üreten deneyim varsa, esp birisi bu tür şeyleri bana rehberlik verebilir umuyoruz.

talep beri, ben burada tablo yapıları koyacağız

CREATE TABLE `shopitems` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `ShopID` int(10) unsigned NOT NULL,
  `ImageID` int(10) unsigned NOT NULL,
  `name` varchar(100) NOT NULL,
  `description` varchar(255) NOT NULL,
  `pricing` varchar(45) NOT NULL,
  `datetime_created` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

/*Table structure for table `shops` */

DROP TABLE IF EXISTS `shops`;

CREATE TABLE `shops` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(100) default NULL,
  `description` text,
  `keywords` text,
  `url` varchar(255) default '',

  `owner_id` varchar(255) default NULL,
  `datetime_created` datetime default NULL,
  `created_by` varchar(255) default NULL,
  `datetime_modified` datetime default NULL,
  `modified_by` varchar(255) default NULL,

  `overall_rating_avg` decimal(4,2) default '0.00',


  PRIMARY KEY  (`id`),
  FULLTEXT KEY `url` (`url`),
  FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM AUTO_INCREMENT=3051 DEFAULT CHARSET=utf8;

i shopproducts tablo açıklama ve adı sütun arama niyetinde.

Gördüğünüz gibi ama henüz uygulamaya konmamıştır.

mağazalar için arama ve çalışıyor zaten olmasına rağmen.

7 Cevap

İşte bu sorunu çözmek için akılda tutulması gereken birkaç "oyunun kuralları" vardır. Muhtemelen bu zaten biliyorum, ama bunları açıkça belirten onaylamak diğer okuyucular için yardımcı olabilir.

  • MySQL tüm indeksleri tek bir temel tablo sütunları başvurabilirsiniz. Sen bir tam dizin yapamazsınız birden çok tablo arasında indeksler.
  • Sen, görünümleri için sadece temel tablolar dizinleri tanımlamak olamaz.
  • Tam dizin karşı bir MATCH() sorgu endeksi ilan sırayla, tam dizin tüm sütunları karşı eşleşmesi gerekir.

Senin dizin istediğiniz içeriği depolamak için üçüncü bir tablo yaratacak. Yedekli bu içeriği depolamak gerek yok - bu yalnızca üçüncü tabloda depolamak. Bu nesne yönelimli tasarım (biz RDBMS tasarım uygulayabilirsiniz sürece) bir "ortak sınıftan" kavramını ödünç alır.

CREATE TABLE Searchable (
  `id` SERIAL PRIMARY KEY,
  `title` varchar(100) default NULL,
  `description` text,
  `keywords` text,
  `url` varchar(255) default '',
  FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shopitems` (
  `id` INT UNSIGNED NOT NULL,
  `ShopID` INT UNSIGNED NOT NULL,
  `ImageID` INT UNSIGNED NOT NULL,
  `pricing` varchar(45) NOT NULL,
  `datetime_created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shops` (
  `id` INT UNSIGNED NOT NULL,
  `owner_id` varchar(255) default NULL,
  `datetime_created` datetime default NULL,
  `created_by` varchar(255) default NULL,
  `datetime_modified` datetime default NULL,
  `modified_by` varchar(255) default NULL,
  `overall_rating_avg` decimal(4,2) default '0.00',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Otomatik artışlı anahtar ile tek tablo fark artık Searchable. Tablolar shops ve shopitems uyumlu bir veri türüne sahip bir anahtar kullanmak, ancak otomatik artış. Yani, ya shops veya shopitems karşılık gelen satır oluşturabilirsiniz önce Searchable, id değeri oluşturmak için bir satır oluşturmak gerekir .

MyISAM bu kısıtlamaları sessizce göz ardı eder (ve zaten tam dizin oluşturma desteği sağlamak için MyISAM kullanmanız gerekir bildiğiniz) halde, illüstrasyon amaçlı FOREIGN KEY bildirimleri ekledim.

Şimdi bir tek tam dizini kullanarak, tek bir sorguda iki shops ve shopitems metinsel içeriğini arama yapabilirsiniz:

SELECT S.*, sh.*, si.*,
  MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;

Tabii ki, Searchable sadece bir tablo uymalıdır belirli bir satır için, dükkanları veya shopitems ve bu tablolar ya farklı sütunlar vardır. Yani ya sh.* veya si.* sonuç null olacaktır. Bu uygulama çıktı biçimlendirmek için size kalmış.


Diğer yanıtlar birkaç Sphinx Search kullanarak sürmüştür. Bu MySQL tamamlar ve daha sofistike tam metin arama özelliği ekler başka bir teknolojidir. Bu sorguları için büyük bir performansa sahiptir, bu yüzden bazı insanlar onunla çok büyülü aldık.

Ancak dizin oluşturma ve özellikle bir dizin ekleme aşamalı pahalıdır. Aslında, bir Sfenks arama dizini güncelleştirme önerilen çözümü biri eski, arşivlenmiş veri kütüğü ve güncelleştirilmesi için daha büyük olasılıkla son veriler için başka küçük bir dizin oluşturmak için o kadar pahalı. Sonra her arama iki ayrı dizinler karşı iki sorguları çalıştırmak zorundadır. Veri doğal olarak eski veri değişmez olma desen elverişli değildir ve eğer, o zaman zaten bu hile yararlanmak mümkün olmayabilir.


Yorumlarınız Re: İşte bir endekse canlı güncelleştirmeler hakkında Sphinx Search documentation bir alıntı var:

There's a frequent situation when the total dataset is too big to be reindexed from scratch often, but the amount of new records is rather small. Example: a forum with a 1,000,000 archived posts, but only 1,000 new posts per day.

In this case, "live" (almost real time) index updates could be implemented using so called "main+delta" scheme.

Fikir Sphinx arama dizini güncelleştirmek pahalı olduğundan, bunların çözümü mümkün güncellemek indeks olarak küçük yapmak olmasıdır. Böylece (kendi örnekte) sadece en son forum mesaj, bir kez bu koleksiyon için bir ikinci, daha büyük bir dizin oluşturmak böylece arşivlenmiş forum büyük geçmişini asla değiştirir, oysa. Eğer bir arama yapmak istiyorsanız Tabii ki, her iki dizin sorgulamak zorunda.

Düzenli olarak, haftada bir kez söylüyorlar, "son" için forum mesajları kabul "arşivlenen" ve arşivlenmiş endeksi son mesajlar için geçerli dizin birleştirmek olurdu olmak ve küçük dizin başlamak istiyorum. Bunlar, iki Sphinx arama dizinleri birleştirme veri için bir güncelleştirme sonra yeniden dizin daha verimli olduğu noktaya yapmak.

Ama benim açımdan set değil, her veri doğal olarak sık güncelleştirmeler yeni veriler karşısında asla değişmez bir veri arşivlenmiş seti, sahip desen içine düşüyor olmasıdır.

Örneğin veritabanı atın: dükkan ve shopitems var. Nasıl bu yeni satırlar hiç değişmez, satır içine ayırabilirsiniz? Katalogda herhangi bir dükkan veya ürünleri kendi güncellemek için izin verilmelidir. O tüm Sphinx arama dizinini bir değişiklik yapmak her zaman yeniden inşa etmek gerekir çünkü Ama çok pahalı bir işlem haline gelir. Belki de değişiklikleri sıraya ve haftada bir dizin yeniden bir toplu bunları uygulamak istiyorum. Ama dükkan açıklamasına bir küçük değişiklik Pazar gecesi kadar etkili olmaz, neden mağaza satıcılarının açıklayan deneyin.

Ben doğru anladım emin değilim, ama burada benim 2 sent vardır.

Görebildiğim kadarıyla, sorun çok farklı düzenleri ile 2 tablolar var olduğunu, bu yüzden bu alanlarda tam arama dayandırmak istediğinizi varsayalım olacak:

  • başlık, açıklama ve anahtar kelimeler: shops için
  • adı ve açıklaması: shopitems için

Solution 1: Layout consistency -- does not use index...

Eğer bir şekilde shopitems için sütun adını değiştirmek olsaydı, hemen çok daha basit olacaktı.

Select id From
(Select id, text1, text2, text3 From table1
 UNION
 Select id, text1, text2, text3 From table2)
Where MATCH(id, text1, text2, text3) AGAINST('keyword1 keyword2 keyword3')

Ancak ben zaten var her şeyi değiştirmek için pratik olacağını anlayabiliyorum. shopitems olsa hile yapabileceği üçüncü bir (kukla) metin sütun ekleyerek, aliasing ile unutmayın.

Solution 2: Post-treatment

Ben hesaplanan değeri aslında döndü (ve dolayısıyla kullanılan) olabilir belirtmeliyiz. Bu nedenle, bu değeri ile geçici bir tablo oluşturabilirsiniz! Eğer 'başlığı' ve 'açıklamasını' iade etmek isterseniz iki sütun bir unifrom bir şekilde ele alınması gereken aynı türde olması gerektiğini unutmayın ...

Select id, title, description From
(
 Select id, title, description, MATCH(id, title, description, keywords) AGAINST('dummy') As score
        From shops
        Where MATCH(id, title, description, keywords) AGAINST('dummy')
 UNION
 Select id, name As title, description, MATCH(id, name, description) AGAINST('dummy') As score
        From shopitems
        Where MATCH(id, name, description) AGAINST('dummy')
)
ORDER BY score DESC

Ben mysql Seçer her / eşleşmeye karşı çift çağrısı (ben öyle umuyorum) uzak optimize edecek merak ediyorum, ama bu sorgu performansı hiçbir fikrim yok.

Yakalamak benim sorgu sadece bir gösteri olmasıdır. Aliasing kullanmanın dezavantajı artık gelen hangi tablo artık bilmiyorum olmasıdır.

Her neyse, ben sana yardımcı umuyoruz.

Sana ilk seçeneği öneririz. Fazlalık her zaman kötü değildir.

Yani böyle bir tablo yapmak istiyorum:

CREATE TABLE search_results
(
   ...
   `searchable_shop_info` VARCHAR(32),
   `searchable_shopitem_info` TEXT
   FULLTEXT KEY `searchable` (`searchable_shop_info`, `searchable_shopitem_info`)
) Engine=MyISAM;

Sonra yine kullanabilirsiniz SELECT * FROM search_results WHERE MATCH ( searchable_shop_info , searchable_shopitime_info ) AGAINST ('search query string');

hmm belki u sendika kullanabilirsiniz? gibi

create table search1 (
    title varchar(12), 
    relavency tinyint unsigned
);

create table search2 (
    title varchar(12), 
    relavency tinyint unsigned
);

insert into search1 values (substring(md5(rand()), 1, 12), (rand()*100)), 
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100));

insert into search2 values (substring(md5(rand()), 1, 12), (rand()*100)), 
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100)),
(substring(md5(rand()), 1, 12), (rand()*100));

(select *, 'search1' as source from search1) 
union (select *, 'search2' as source from search2) 
order by relevancy desc;

Lütfen satırları seçin ve sonuçları sendika sonra normal başına alaka hesaplamak. i u yolu yanlış anlaşıldığı takdirde kimse sendikaya düşünüyor çünkü ben bilmiyorum?

alt text

UPDATE 1:

ok i ur soru ve yorum zaten ... bence yeniden okumak

1) should i change my design? i am thinking of having a separate table called search results that will contain data from both SHOPS and SHOPPRODUCTS table. however that means i have some data duplication.

i u bir görünüm otomatik olarak "update" ur veri değişiklikleri gibi iki tablodan verileri içermesi için, bunun yerine bir görünümü kullanmak shld düşünüyorum. u bir tablo kullanırsanız, u muhtemelen bunu urself güncellemeniz gerekir.

CREATE VIEW viewSearch (Title, Relavency, SourceTable) AS 
(SELECT title, relavency, 'search1' as source FROM search1
ORDER BY relavency DESC
LIMIT 10)
UNION 
(SELECT title, relavency, 'search2' as source FROM search2
ORDER BY relavency DESC
LIMIT 10)
ORDER BY relavency DESC 
LIMIT 10;

alt text

2) should i keep my current design? if so, then how on earth can i get the search results sorted by relevancy across 2 different tables?

yapabilirsiniz Yukarıdaki SQL / görüntüle. temel olarak yerleştirerek

...
ORDER BY relavency DESC 
LIMIT 10

i am curious. that means i need to run that query EVERYTIME for any search input. because different input would have different relevancy scores.

i gerçekten u ne demek dont almak? u anda 2 tablo arasında aramak için olsaydı, alışkanlık u (her tablo için 1) 2 ayrı SQL sorguları do? ya u aslında 3 sorguları (2 sorguya sonra sonuçlar tabloya 1 seçmek için) ... onun hala 1 tabloya sonuçlarını seçmek olsaydı.

ben de ORDER BY & ekledik Her içine SINIR az kayıtlarını alarak sürecini hızlandırmak için SEÇ. sonra SİPARİŞ BY & Bir bütün olarak bir kez daha LİMİT.

Bu örnekte, i alaka hesaplamak nasıl bilmiyorum, bu yüzden bunun için rasgele numaralar kullandık.

Maybe i am a bit lacking in understanding. i am suspicious whether your method is resource intensive. Please enlighten me. I am willing to consider all possibilities.

Ben dürüst olmak gerçekten emin değilim, ama bu cevap bilmek gibi olacak ... ben yine de birden fazla sorgu daha iyi olacak tahmin ediyorum.

Bu yöntem, herhangi bir şeyi etkiler eğer oh ve ben tam metin arama ile gerçekten aşina değil de duyuyorum bu yüzden ben bilmiyorum

Ben soruları doğru anlamak, cevap çok basit:

  1. Tasarımını değiştirmek etmeyin. O gayet iyi. Olması gerektiği gibi değil.
  2. Bu gibi birleştirilmiş bir sorgu yapın:
SELECT * FROM shops
LEFT OUTER JOIN shopitems ON (shopitems.shopid = shops.id)
WHERE 
    MATCH (shops.title, shops.description, shops.keywords,
           shopitems.name, shopitems.description) 
    AGAINST ('whatever text')

Ben UNION için giderdim. Bu deyimi thepurpose olduğunu.

Ben ayrı bir arama tablosu oluşturarak, ilk alternatif ile gitmek istiyorum.

Biz birkaç SOA sistemleri arasında veri aramak için gerektiğinde biz bu kez yaptık.

Bu yaklaşımın avantajları şunlardır:

  • arama isteklerine daha hızlı yanıt
  • Arama sonuçlarının organize üzerinde daha fazla kontrol

Sakıncaları şunlardır:

  • iki yerde yazılmış olmalıdır beri, verileri kaydetmek için yavaş zamanı
  • veri depolamak için kullanılan fazladan bir boşluk