Συνδυαστικά φίλτρα eshop

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Άβαταρ μέλους
jpk
Δημοσιεύσεις: 441
Εγγραφή: 09 Μαρ 2011 21:17

Συνδυαστικά φίλτρα eshop

Δημοσίευση από jpk » 03 Μάιος 2011 04:55

Μην νευριάζεις … η πρώτη μου ερώτηση ήταν πως το σκέφτηκες όλο αυτό με τα filters από την αρχή … σίγουρα έχω να κάνω με μπερδεμένο data model αφού δεν είχες μια απλή απάντηση .. θα δώ τους πίνακες σου και θα σου πω αν υπάρχει περίπτωση να βγάλεις άκρη ακόμα και με αυτούς… Αν έχεις πάντων καμία όρεξη να μοιραστείς πια ήταν τα specs σου … προδιαγραφές … και να το φτιάξουμε από την αρχή θα ήταν καλλίτερο

Άβαταρ μέλους
Khronos
Δημοσιεύσεις: 754
Εγγραφή: 11 Δεκ 2006 14:43
Τοποθεσία: Ηράκλειο

Συνδυαστικά φίλτρα eshop

Δημοσίευση από Khronos » 03 Μάιος 2011 10:19

@ggirtsou

Μόνο ένας fafos θα σου δώσει ουσιαστική απάντηση όπως δείχνουν τα πράγματα. :P

Άβαταρ μέλους
korgr
Honorary Member
Δημοσιεύσεις: 5067
Εγγραφή: 07 Οκτ 2008 18:30
Τοποθεσία: Corinth
Επικοινωνία:

Συνδυαστικά φίλτρα eshop

Δημοσίευση από korgr » 03 Μάιος 2011 11:13

jpk αυτό είναι το σημείο που αντιδρούμε στα λεγόμενα "αγγλικά".
Το Data Model όπως το εννοείς προφανώς περιγράφει μια μεθοδολογία. Αντί να μας πεις με έναν αγγλικό όρο ποιο Data Model θα χρησιμοποιούσες εσύ, καλύτερα ανέλυσε την ουσία (την φιλοσοφία που κρύβεται πίσω από τον όρο).

Ο άνθρωπος σου μιλάει με ουσία και εσύ απαντάς με θεωρητικολογίες!
Σου λέει έχει ένα bridge table `products_filters` ο οποίος γεφυρώνει τους πίνακες `filters` και `products` περιέχοντας σε κάθε εγγραφή του τα productID και filterID. Τι δεν καταλαβαίνεις και θες να σου πει για Data Models και άλλα πανεπιστημιακά εύηχα?

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Συνδυαστικά φίλτρα eshop

Δημοσίευση από pimpogio » 03 Μάιος 2011 11:22

εχει λαθος σχημα/σκεψη ο φιλος...

τα φιλτρα ειναι βασισμενα σε ιδιοτητες των προιοντων (και οι ιδιοτητες πρεπει να μπαινουνε δυναμικα/δεν ειναι εκ των προτέρων καθορισμενες) οποτε:
products(pid,title,desc....)
properties(propid,name)
products_properties(pid,propid,value) pid fk sto products(pid) propid fk sto properties(propid)

αυτο μου ειρθε τωρα δεν ξερω αμα γινετε καλυτερα...

αν εχει κανεις καλυτερη ιδεα..

kapoios001
Δημοσιεύσεις: 403
Εγγραφή: 17 Φεβ 2011 12:26

Συνδυαστικά φίλτρα eshop

Δημοσίευση από kapoios001 » 03 Μάιος 2011 12:27

Και εγώ αυτό το πράγμα έκανα απλώς με άλλη λογική.

Η λογική είναι η εξής: αποθηκεύω στον πίνακα products το προϊόν μου και για να δω τι "φίλτρα" έχει τότε πάω στον products_filters και βλέπω όπου product_ID = X τότε έχει αυτά τα φίλτρα. Παίρνω τα ID των φίλτρων και πάω στον πίνακα filters_details και παίρνω τον τίτλο του φίλτρου και το value του.

Το ίδιο πράγμα λες εσύ το ίδιο πράγμα λέω και εγώ. Απλώς εγώ το έκανα με περισσότερους πίνακες γιατί νόμιζα ότι ήταν καλύτερα έτσι. Με την παρούσα δομή όπως το έχω κάνει μπορώ με μερικά query να έχω το αποτέλεσμα που θέλω;

Δηλαδή βάση των φίλτρων που επιλέγει ο χρήστης να εμφανίζει τα ανάλογα προϊόντα με τα ανάλογα χαρακτηριστικά;

Ορίστε τα δεδομένα του filters_details:

Κώδικας: Επιλογή όλων

INSERT INTO `filters_details` (`filter_ID`, `lang_ID`, `title`, `value`) VALUES
(1, 1, 'Φίλτρο', 'Περιεχόμενα'),
(2, 1, 'Κατασκευαστής', 'Turbo-X'),
(3, 1, 'Κατασκευαστής', 'ACER'),
(4, 1, 'Κατασκευαστής', 'Sony'),
(6, 1, 'Κατασκευαστής', 'Toshiba'),
(7, 1, 'Συνιστώμενη Χρήση ', 'Υψηλών επιδόσεων '),
(8, 1, 'Συνιστώμενη Χρήση ', 'Για απλή χρήση'),
(9, 1, 'Συνιστώμενη Χρήση ', 'Επαγγελματικά'),
(10, 1, 'Συνιστώμενη Χρήση ', 'Ευελιξία Μετακίνηση'),
(11, 1, 'Συνιστώμενη Χρήση ', 'Ήχου Εικόνας'),
(12, 1, 'Εύρος οθόνης (inches) ', '15 έως 16 inches'),
(13, 1, 'Εύρος οθόνης (inches) ', '16 έως 18,4 inches'),
(14, 1, 'Εύρος οθόνης (inches) ', 'μικρότερη από 15 inches '),
(15, 1, 'Μνήμη Κάρτας Γραφικών', '1024 MB'),
(16, 1, 'Μνήμη Κάρτας Γραφικών', '128 MB'),
(17, 1, 'Μνήμη Κάρτας Γραφικών', '1536 MB'),
(18, 1, 'Μνήμη Κάρτας Γραφικών', '2048 MB'),
(19, 1, 'Μνήμη Κάρτας Γραφικών', '256 MB'),
(20, 1, 'Μνήμη Κάρτας Γραφικών', '512 MB ');

Άβαταρ μέλους
jpk
Δημοσιεύσεις: 441
Εγγραφή: 09 Μαρ 2011 21:17

Συνδυαστικά φίλτρα eshop

Δημοσίευση από jpk » 03 Μάιος 2011 12:50

Korgr το καλλίτερο θα ήταν όντως να διαβάσουμε την μεθοδολογία αλλά έγραψα και κάτι άλλο (για την δομή των δεδομένων και πώς την σκέφτηκε ) ο ggirtsou . Ναι το πώς ακριβώς λειτουργεί ο πίνακας «γεφυρώσεων» ρωτούσα. Τώρα που έχει παράσχει περισσότερες πληροφορίες ο ggirtsou κάπως έχω αρχίσει να καταλαβαίνω πως λειτουργεί.

Πέρα από αυτό μια ερώτηση ggirtsou , που νομίζω θα βοηθήσει, όταν κάνεις var_dump τα $criteria ακριβώς πριν το query έχει μέσα του τα «φίλτρα» που περιμένεις σωστά κάθε φορά;

Άβαταρ μέλους
fafos
Script Master
Δημοσιεύσεις: 6236
Εγγραφή: 30 Νοέμ 2004 03:09

Συνδυαστικά φίλτρα eshop

Δημοσίευση από fafos » 03 Μάιος 2011 14:18

ggirtsou... dose mas kai thn data me ta paradeigmata pou exeis sthn vash (proionta, categories klp)
Οι πάνες και οι πολιτικοί πρέπει να αλλάζονται συχνά για τον ίδιο λόγο...

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Συνδυαστικά φίλτρα eshop

Δημοσίευση από pimpogio » 03 Μάιος 2011 16:39

η βαση σου δεν ειναι normalized...
κανε αυτο που σου ειπα παραπανω νομιζω οτι αυτη ειναι η λυση που θες

Άβαταρ μέλους
cherouvim
Script Master
Δημοσιεύσεις: 3137
Εγγραφή: 13 Ιούλ 2005 22:56
Τοποθεσία: Athens, Greece
Επικοινωνία:

Συνδυαστικά φίλτρα eshop

Δημοσίευση από cherouvim » 03 Μάιος 2011 18:59

Το σίγουρο είναι οτι με αυτό δεν θα έχεις καθόλου αποτελέσματα:

Κώδικας: Επιλογή όλων

AND products_filters.filter_ID = '8'
AND products_filters.filter_ID = '2'
AND products_filters.filter_ID = '19'
Για να φέρεις product ids τα οποία έχουν φίλτρα το 8 ή το 2 ή το 19 θέλεις:

Κώδικας: Επιλογή όλων

AND products_filters.filter_ID in (8, 2, 19)
Για να φέρεις product ids τα οποία έχουν φίλτρα το 8 και το 2 και το 19 (και πιθανώς και άλλα) θέλεις κάτι τέτοιο:

Κώδικας: Επιλογή όλων

select p.product_id from 
  products p, filters f, products_filters pf
where
  pf.product_id=p.product_id and pf.filter_id=f.filter_id and
  pf.filter_ID in (8, 2, 19)
group by
  p.product_id having count(*)>=3
;
το >=3 είναι το πλήθος των φίλτρων που έχεις στο in.

Η λύση είναι από την ιδέα του dva_dev στο http://www.freestuff.gr/forums/viewtopic.php?t=43405

kapoios001
Δημοσιεύσεις: 403
Εγγραφή: 17 Φεβ 2011 12:26

Συνδυαστικά φίλτρα eshop

Δημοσίευση από kapoios001 » 03 Μάιος 2011 20:18

Δεδομένα πίνακα products:

Κώδικας: Επιλογή όλων

INSERT INTO `products` (`product_ID`, `category_ID`, `tax_ID`, `start_date`, `end_date`, `status`, `logo`, `weight`, `price`, `discount`, `embed_code`, `front_page`, `product_code`, `quantity`, `creation_date`) VALUES
(5, 6, 1, 0, 0, 1, '1519794.jpgLARGEHcLVz1303823826.jpg', 1.5, 399, 0, '', 1, '1519794', 15, '2011-04-27 11:57:15'),
(6, 6, 1, 0, 0, 1, '1636278_LARGEabOc51303825622.jpg', 1.5, 450, 0, '', 1, '1636278', 20, '2011-04-27 15:40:39');
Δεδομένα πίνακα products_details:

Κώδικας: Επιλογή όλων

INSERT INTO `products_details` (`product_ID`, `lang_ID`, `title`, `description`) VALUES
(5, 1, 'HP Pavilion dm1-1200/2000ev/sv ', 'Με πάχος μόλις 2cm για φορητότητα, LED οθόνη 11,6" και μεγάλη διάρκεια μπαταρίας.'),
(6, 1, 'Turbo-X Steel C 35-232 ', 'Το Πλαίσιο παρουσιάζει τη σειρά laptop Turbo-X Steel, σχεδιασμένη για δυνατή απόδοση και μέγιστη ψυχαγωγία με την πιο σύγχρονη τεχνολογία γραφικών.\r\n\r\nΤο νέο Steel C 35-232 είναι εξοπλισμένο με μια οθόνη widescreen 15,6" ιδανική για να εργαστείτε και να ψυχαγωγηθείτε με άνεση και ευκολία. Διαθέτει ανάλυση 1366x768 και πραγματικά πανοραμική απεικόνιση 16:9, και προσφέρει την καλύτερη δυνατή εμπειρία ψηφιακών μέσων. Απολαύστε εικόνες και γραφικά με ρεαλισμό και εξαιρετική ευκρίνεια ή εναλλακτικά χρησιμοποιήστε την έξοδο HDMI για να συνδεθείτε με οποιαδήποτε HD τηλεόραση και να μεταφέρετε την δράση στην μεγάλη οθόνη.\r\n\r\nΣτα υπόλοιπα τεχνικά χαρακτηριστικά το νέο Steel είναι εφοδιασμένο με διπύρηνο επεξεργαστή Intel Celeron T3500, για επαρκή απόδοση με βελτιωμένη διάρκεια μπαταρίας, καθώς και μνήμη 2GΒ (με δυνατότητα επέκτασης έως και 4GB) για ταχύτητα στις εφαρμογές. Παράλληλα τα 320GB χωρητικότητας του σκληρού δίσκου θα αποδειχτούν αρκετά για να φιλοξενήσουν τον βασικό όγκο των δεδομένων σας.\r\n\r\n    Συνδεθείτε με ιδιαίτερη ευκολία σε κάθε δίκτυο μέσω της θύρας Ethernet ή με την ασύρματη τεχνολογία Wi-Fi.\r\n    H ενσωματωμένη web κάμερα 1.3 Μegapixel σας επιτρέπει να κρατήσετε εύκολα επαφή με φίλους και συναδέλφους μέσω βίντεο κλήσεων ή να αποστείλετε φωτογραφίες.\r\n    Για τη σύνδεση με εξωτερικές συσκευές υπάρχει ενσωματωμένο 7-σε-1 card reader, τρεις θύρες USB, μια αναλογική θύρα οθόνης, ενώ δεν λείπουν και οι απαραίτητες έξοδοι και είσοδοι ήχου.');
Δεδομένα πίνακα products_filters:

Κώδικας: Επιλογή όλων

INSERT INTO `products_filters` (`product_ID`, `filter_ID`) VALUES
(5, 8),
(5, 12),
(5, 14),
(5, 19),
(6, 2),
(6, 8),
(6, 12),
(6, 19);
cherouvim αυτό που μου είπες τώρα δουλεύει και εμφανίζει σωστά τα προϊόντα σύμφωνα με τα επιλεγμένα φίλτρα.

Αυτό που δεν μπόρεσα να κάνω να δουλέψει είναι να εμφανίζει το count σωστό για το κάθε φίλτρο.

Για να το εξηγήσω καλύτερα ανεβάζω δύο screenshot. Στην εικόνα 1 θα δείτε ότι τα φίλτρα που εμφανίζονται έχουν σωστό count (πχ έχω ένα Turbo-X laptop, οπότε στους Κατασκευαστές το Turbo-x είναι 1).

Όταν επιλεχθεί κάποιο φίλτρο όμως, τότε το count του Turbo-X γίνεται 2 και εμφανίζονται και όλα τα υπόλοιπα φίλτρα που από 0 πήραν τιμές 1,2.

Τώρα το function για το count είναι:

Κώδικας: Επιλογή όλων

function ProductsFiltersLink($filter_ID, $filtering) {
	$filtering_sql = $criteria = array();
	if (!empty($filter_ID)) {
		$criteria[] = $filter_ID;
	}

	if (!empty($filtering)) {
		foreach($filtering as $filteringID) {
			$criteria[] = $filteringID;
		}
	}

	$sql = "select p.product_id from
		  products p, filters f, products_filters pf\n";
	if (!empty($criteria)) {
		$sql .=	"WHERE pf.product_id=p.product_id and pf.filter_id=f.filter_id and
  pf.filter_ID in (".implode(', ',$criteria).")\n";
	}

	$sql .= "group by
  p.product_id having count(*)>=".count($filtering)."\n";

	if ( ! ( $result = mysql_query($sql) ) ) {
		front_error('Could not execute MySQL query.');
	}

	$rows = mysql_num_rows($result);
	if ($rows == 0) {
		return '0';
	}
	else {
		return $rows;
	}
}
Ευχαριστώ πολύ.
Συνημμένα
eikona2.png
Εικόνα 2
(12.88 KiB) Μεταφορτώθηκε 304 φορές
category.png
Εικόνα 1
category.png (7.96 KiB) Προβλήθηκε 2219 φορές

Άβαταρ μέλους
cherouvim
Script Master
Δημοσιεύσεις: 3137
Εγγραφή: 13 Ιούλ 2005 22:56
Τοποθεσία: Athens, Greece
Επικοινωνία:

Συνδυαστικά φίλτρα eshop

Δημοσίευση από cherouvim » 03 Μάιος 2011 22:27

Ναι, το faceted search που δίνεις μπορεί να βασιστεί στο query που σου έδωσα (ιδέα του dev_dva). Το θέλεις και αυτό ή θα προσπαθήσεις πρώτα μόνος σου;

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Συνδυαστικά φίλτρα eshop

Δημοσίευση από dva_dev » 04 Μάιος 2011 00:41

Καλησπέρα, (ψιλοχάνομαι τώρα τελευταία γιατί πήζω, αλλά ελπίζω).

Μου φαίνεται ότι το σχήμα μας το δείχνεις μισό (αλλά δεν πειράζει, άκρη στο περίπου ψιλοβγαίνει και έτσι).

Αν χρησιμοποιείς, για να φέρεις τα product_ids και να δείξεις τα προϊόντα με τα κριτήρια που έχεις επιλέξει, ένα query του στύλ

Κώδικας: Επιλογή όλων

select pf.product_id, COUNT(pf.filter_ID) countFilters from
products p
INNER JOIN products_filters pf ON (pf.product_id=p.product_id)
where pf.filter_ID in (8, 19)
AND p.quantity > 0
group by pf.product_id
having COUNT(pf.filter_ID)=2
Για να δείξεις πόσα προϊόντα υπάρχουν που να ικανοποιούν αυτά (οπωσδήποτε), αλλά και άλλα πιθανά κριτήρια, ίσως μπορούσες να χρησιμοποιήσεις ένα query του στυλ

Κώδικας: Επιλογή όλων

select pf.filter_ID, COUNT(pf.product_ID) countProducts
from products_filters pf
inner join
(
    select pf.product_id, COUNT(pf.filter_ID) countFilters from
    products p
    INNER JOIN products_filters pf ON (pf.product_id=p.product_id)
    where pf.filter_ID in (8, 19)
    AND p.quantity > 0
    group by pf.product_id
    having COUNT(pf.filter_ID)=2
)tmp
on pf.product_id = tmp.product_id
GROUP BY pf.filter_ID
Αν προσέξεις μέσα στο (...) tmp είναι το παραπάνω query που φέρνει τα product_IDs που ικανοποιούν τα κριτήρια, οπότε και τα αποτελέσματα που φέρνεις για να δείξεις αλλά και τα αθροίσματα που δείχνουν τα κριτήρια πρέπει να περιοριστούν με κάποιο τρόπο (με join με in με οτιδήποτε τέλος πάντως) σε αυτά που φέρνει το subquery.

Στο subquery tmp, αφού ζητάμε τα κριτήρια να είναι in (8,2,19) είναι νομίζω υπερβολή να ζητάμε στο having count() >=3 αφού θα έχει μέχρι 3 αποτελέσματα, και στη συγκεκριμένη περίπτωση του (8,19) θα είναι μέχρι 2.

Μέσα στο where του subquery, βάζεις και ότι άλλα κριτήρια νομίζεις, π.χ. το quantity>0.

Ισως μπορεί να γίνει πιο εύκολα ή πιο γρήγορα χρησιμοποιώντας την (not) exists. Οποιος έχει χρόνο και όρεξη το ψάχνει και μας λέει.

cherouvim έγραψε:...ιδέα του dev_dva...
Πάρτο αλλιώς... :D

Άβαταρ μέλους
cherouvim
Script Master
Δημοσιεύσεις: 3137
Εγγραφή: 13 Ιούλ 2005 22:56
Τοποθεσία: Athens, Greece
Επικοινωνία:

Συνδυαστικά φίλτρα eshop

Δημοσίευση από cherouvim » 04 Μάιος 2011 09:37

dva_dev έγραψε:Στο subquery tmp, αφού ζητάμε τα κριτήρια να είναι in (8,2,19) είναι νομίζω υπερβολή να ζητάμε στο having count() >=3 αφού θα έχει μέχρι 3 αποτελέσματα, και στη συγκεκριμένη περίπτωση του (8,19) θα είναι μέχρι 2.
Σωστός!
dva_dev έγραψε:
cherouvim έγραψε:...ιδέα του dev_dva...
Πάρτο αλλιώς... :D
Σωστός!

kapoios001
Δημοσιεύσεις: 403
Εγγραφή: 17 Φεβ 2011 12:26

Συνδυαστικά φίλτρα eshop

Δημοσίευση από kapoios001 » 07 Μάιος 2011 13:01

Παιδιά ευχαριστώ πολύ για τις απαντήσεις σας.

Όντως δουλεύει το query, το έτρεξα σε phpmyadmin και προσπάθησα να το προσαρμόσω στο function μου αλλά δεν το κατάφερα.

Ενώ δουλεύει σε phpmyadmin δεν μου εμφανίζει το count σωστά στο μπροστά μέρος επειδή δεν κάνω build σωστά το query μέσα στο function.

Το προσπάθησα αρκετές φορές αλλά δεν το κατάφερα.

Μπορείτε να με βοηθήσετε να το βάλω μέσα στο function;

Ορίστε τι έχω κάνει:

Κώδικας: Επιλογή όλων

function ProductsFiltersLink($filter_ID, $filtering) {
	$filtering_sql = $criteria = array();
	if (!empty($filter_ID)) {
		$criteria[] = $filter_ID;
	}

	if (!empty($filtering)) {
		foreach($filtering as $filteringID) {
			$criteria[] = $filteringID;
		}

$sql = "select pf.filter_ID, COUNT(pf.product_ID) countProducts
from products_filters pf
inner join
(
    select pf.product_id, COUNT(pf.filter_ID) countFilters from
    products p
    INNER JOIN products_filters pf ON (pf.product_id=p.product_id)\n";
	if (!empty($criteria)) {
		$sql .= "where pf.filter_ID in (".implode(', ', $criteria).")\n";
	}

	if (empty($criteria)) {
		$sql .= " WHERE p.quantity > 0\n";
	}
	else {
	    $sql .= "AND p.quantity > 0\n";
	}

	$sql .= "group by pf.product_id
    having COUNT(pf.filter_ID)=2
)tmp
on pf.product_id = tmp.product_id
GROUP BY pf.filter_ID";

	}
	else {
		$sql = "select p.product_id from
			  products p, filters f, products_filters pf\n";
		if (!empty($criteria)) {
			$sql .=	"WHERE pf.product_id=p.product_id and pf.filter_id=f.filter_id and
	  pf.filter_ID in (".implode(', ',$criteria).")\n";
		}

		$sql .= "group by p.product_id having count(*)>=".count($filtering)."\n";
	}

	if ( ! ( $result = mysql_query($sql) ) ) {
		front_error('Could not execute MySQL query.');
	}

	$rows = mysql_num_rows($result);
	if ($rows == 0) {
		return '0';
	}
	else {
		if (!empty($filtering)) {
			$row = mysql_fetch_array($result);
			echo print_r($row);
			if ($row['filter_ID'] == $filter_ID) {
				return $row['countProducts'];
			}
		}
		else {
			return $rows;
		}
	}
}
Ευχαριστώ πολύ.

Άβαταρ μέλους
jpk
Δημοσιεύσεις: 441
Εγγραφή: 09 Μαρ 2011 21:17

Συνδυαστικά φίλτρα eshop

Δημοσίευση από jpk » 07 Μάιος 2011 13:12

Μπορεί να είναι άσχετο μπορεί και όχι … το ξαναρώτησα πριν μέρες … Πέρα από αυτό μια ερώτηση ggirtsou , που νομίζω θα βοηθήσει, όταν κάνεις var_dump τα $criteria ακριβώς πριν το query έχει μέσα του τα «φίλτρα» που περιμένεις σωστά κάθε φορά;

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες