woop Posted November 2, 2013 Share Posted November 2, 2013 Hi! I'm trying to create a search function where a search string could be a mix of different fields. eg. "Rowling Potter" should return the post that has both author="J.K Rowling" and title="harry potter". If set up my selector like author|title*=$q, it will won't return anything since it expects the full string to fit into either the author-field or the title one. Link to comment Share on other sites More sharing options...
diogo Posted November 2, 2013 Share Posted November 2, 2013 This should do what you want: // untested $q = str_replace(" ", "|", $q); // replace spaces by pipes $results = $pages->find("author|title*=$q"); Link to comment Share on other sites More sharing options...
woop Posted November 2, 2013 Author Share Posted November 2, 2013 Thanks! This helps me avoid empty results but doesn't seem to help specifying the search further. Eg. "rowling potter" now returns both the right post and other books made by rowling. The ideal result would be to only match the harry potter book by rowling. Does that make sense? Link to comment Share on other sites More sharing options...
Wanze Posted November 2, 2013 Share Posted November 2, 2013 Well in this case you should add two separate fields in the search: author and title. Because you can't know which words belong to authors or titles if there are multiple in the search string. Link to comment Share on other sites More sharing options...
woop Posted November 2, 2013 Author Share Posted November 2, 2013 Not sure I follow. Like author|title*=$q,? Link to comment Share on other sites More sharing options...
diogo Posted November 2, 2013 Share Posted November 2, 2013 What about this? (also written in the browser and not tested at all) // the code was not good // see my next answer Hope it's clear... Link to comment Share on other sites More sharing options...
woop Posted November 2, 2013 Author Share Posted November 2, 2013 Sorry. Doesn't seem to work. I don't get any results at all. Changed makeNew to new PageArray(); since that got me an error. Also removed spaces between id and equalsign in the selector. Still no luck. Thanks anyway! Link to comment Share on other sites More sharing options...
diogo Posted November 2, 2013 Share Posted November 2, 2013 (edited) Ya, there were some problems in the previous code. This one is tested and should work: $queryArray = explode(" ", $q); // create an array with all the words $authorPages = new PageArray(); $titlePages = new PageArray(); $results = new PageArray(); foreach($queryArray as $word) { $authorPages->import($pages->find("author*=$word")); $titlePages->import($pages->find("title*=$word")); } // intersect both arrays by importing common pages to the $results array //foreach($titlePages as $p) { // if ($authorPages->has($p)) $results->import($p); //} // forget the above 3 lines, this is so much better for intersecting two arrays $results = $titlePages->find("id=$authorPages"); echo $results; Edited November 3, 2013 by diogo added new method for intersecting 2 Link to comment Share on other sites More sharing options...
nik Posted November 3, 2013 Share Posted November 3, 2013 This should do it too (slightly modifying what diogo proposed at first and what I guess Wanze was saying as well): $q = str_replace(" ", "|", $q); // find pages having at least one of the words both in author field AND in title field $results = $pages->find("author*=$q, title*=$q"); Plus some sanitation probably. 1 Link to comment Share on other sites More sharing options...
diogo Posted November 3, 2013 Share Posted November 3, 2013 Well, that's more clever for sure Link to comment Share on other sites More sharing options...
woop Posted November 3, 2013 Author Share Posted November 3, 2013 Ya, there were some problems in the previous code. This one is tested and should work: $queryArray = explode(" ", $q); // create an array with all the words $authorPages = new PageArray(); $titlePages = new PageArray(); $results = new PageArray(); foreach($queryArray as $word) { $authorPages->import($pages->find("author*=$word")); $titlePages->import($pages->find("title*=$word")); } // intersect both arrays by importing common pages to the $results array //foreach($titlePages as $p) { // if ($authorPages->has($p)) $results->import($p); //} // forget the above 3 lines, this is so much better for intersecting two arrays $results = $titlePages->find("id=$authorPages"); echo $results; Hm. This doesn't get me any results. How would $titlePages->find("id=$authorPages"); work? Link to comment Share on other sites More sharing options...
woop Posted November 3, 2013 Author Share Posted November 3, 2013 This should do it too (slightly modifying what diogo proposed at first and what I guess Wanze was saying as well): $q = str_replace(" ", "|", $q); // find pages having at least one of the words both in author field AND in title field $results = $pages->find("author*=$q, title*=$q"); Plus some sanitation probably. Thanks! That almost does it, I think. Seems like it requires a match in both author and title, though. It would be fine for searches like "harry rowling", but wouldn't work for just "harry". Here's how I've been trying to solve it (but the code doesn't work). Maybe it clarifies my thinking. $p = new pageArray(); $p->import($pages); $queryArray = explode(" ", $q); // create an array with all the words foreach($queryArray as $word) { $m = $p->find("title|author|year|genre%=$word"); $p = $m; // redefine the pageArray to only include previous matches } Link to comment Share on other sites More sharing options...
woop Posted November 3, 2013 Author Share Posted November 3, 2013 doublepost.. Link to comment Share on other sites More sharing options...
nik Posted November 4, 2013 Share Posted November 4, 2013 Now you've got me confused. I think there's an error in your logic that can't be solved - not with a generic solution anyway. At first you said: Thanks! This helps me avoid empty results but doesn't seem to help specifying the search further. Eg. "rowling potter" now returns both the right post and other books made by rowling. The ideal result would be to only match the harry potter book by rowling. Does that make sense? And then later on: Thanks! That almost does it, I think. Seems like it requires a match in both author and title, though. It would be fine for searches like "harry rowling", but wouldn't work for just "harry". So, you'd like "harry" to return all pages with "harry" in any of your search fields. This could be interpreted as one of the following: give pages with all words in any of the search fields $ret = find("title|author*=$q") // exact phrase actually, but #1 isn't the right one anyway OR give pages with any of the words in any of the search fields $ret = find("title|author*=" . str_replace(" ", "|", $q)); // first solution by diogo OR give pages with at least one of the words in all of the search fields (not necessarily the same word matching all the fields) $q = str_replace(" ", "|", $q); $ret = $pages->find("author*=$q, title*=$q"); // what I proposed earlier Now, if I've understood you right, making a search "rowling potter": should not give all pages with "rowling potter" in any of the search fields (#1) should not give all pages with either "rowling" or "potter" in any of the search fields (#2) should not require "rowling" or "potter" in all of the search fields (#3). Instead, you'd want it to give, hmm, all pages with one of the words matching the title and another one matching the author, unless there aren't any when it should give all pages matching any of the words in any field - or something like that. And we're talking about two words and two fields in this example, while your code example mentions actually four fields already. Looks like an impossible job for a generic selector/code solution. Now looking again what Wanze said I feel like he's been right all along: if you need anything more than a trivial match (one of #1..#3 given above), your only option may well be multiple search fields. One for each search field you need to handle in a special way that is. Then the search would be for example author:"rowling", title:"potter" and you could even give an option to choose whether AND or OR should be used (author: "rowling" AND title:"potter" <--> author:"rowling" OR title:"potter"). Now you actually could build a generic handler. Multiple fields lets the user define more precisely what they're after but then again they also require the user to understand which field to use for different searches. Maybe a generic search field + solution #2 for those who just want to find what they're looking for and an advanced search for those who need to refine their search to get only the results they're really after? If there's lots of data and giving some extra matches along with the exact ones (#2) really is a problem, then an advanced search could be the way to go. My personal preference is one single search field giving properly ranked results instead of a monstrous hard-to-fill form maybe giving me only the one match I'm after, but I see there's a place for the latter as well. Sorry for the (too) long post. I got a little carried away. 6 Link to comment Share on other sites More sharing options...
woop Posted November 4, 2013 Author Share Posted November 4, 2013 Thanks! You've managed to articulate my problem in a much better way than I ever could. I'll have to think some more about this. Advanced search isn't an option, unfortunately. I don't think my users care enough to use one if the standard search doesn't work. I'll probably go with regular search and fall back on #2, so I at least can present some results. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now