Jump to content

Selector match that mixes multiple fields?


woop
 Share

Recommended Posts

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

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

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

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 by diogo
added new method for intersecting
  • Like 2
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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

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

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:

  1. 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  
  2. 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 
  3. 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)
    1. $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. :)

  • Like 6
Link to comment
Share on other sites

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...