Closed Bug 395452 Opened 17 years ago Closed 17 years ago

handle multiple tags in url bar autocomplete

Categories

(Firefox :: Address Bar, defect, P1)

defect

Tracking

()

VERIFIED FIXED
Firefox 3 beta2

People

(Reporter: moco, Assigned: moco)

References

(Blocks 1 open bug)

Details

Attachments

(3 files, 12 obsolete files)

169 bytes, text/html
Details
104.45 KB, image/jpeg
Details
28.87 KB, patch
dietrich
: review+
Details | Diff | Splinter Review
handle multiple tags in url bar autocomplete

mconnor writes:

<mconnor> so if I type two tags, how does that work?
<sspitzerMsgMe> you mean:
<sspitzerMsgMe> mozilla schrep
<sspitzerMsgMe> this is a good question.
<sspitzerMsgMe> it will not do what you want
<mconnor> we should fix that

we should continue to search for "mozilla schrep" but when doing the tag search, we should look for items with both the "mozilla" tag and the "schrep" tag, but also the solo "mozilla schrep" tag, I think.

hmm, what does that mean for "mozilla schrep work" entry?

"mozilla" and "schrep" and "work" OR
"mozilla schrep" and "work" OR
"mozilla" and "schrep and work"?

thoughts?
Flags: in-litmus?
Flags: blocking-firefox3?
note, we search in the bm organizer on tags as well, so we'd want something similar there too.  (I'll log a bug.)
> I'll log a bug.

see bug #395462
Status: NEW → ASSIGNED
Is there a seperate bug for matching multiple terms against page titles and addresses, or would this apply to that as well?

> hmm, what does that mean for "mozilla schrep work" entry?
> 
> "mozilla" and "schrep" and "work" OR
> "mozilla schrep" and "work" OR
> "mozilla" and "schrep and work"?

I think that we should use "" marks as a way to let users tell us that they want a space to be treated as part of the tag, or allow "," as a way of expressing multiple tags.

So typing ...

 mozilla, schrep work    ---> searches for "mozilla" and "schrep work"
 mozilla "schrep work"   ---> searches for "mozilla" and "schrep work"
 mozilla schrep work     ---> searches for "mozilla" and "schrep" and "work"
Flags: blocking-firefox3? → blocking-firefox3+
Litmus Triage Team: i cc Stephen to this bug for the in-litmus request
Target Milestone: --- → Firefox 3 M9
I'm pretty sure the vast majority of users are not going to use any special syntax while searching.  I wish I had specific data on the percent of google searches that contain operators or quotation marks, I've heard that it is very small.  I'm still in favor of allowing users to enter commas and quotation marks to clearly differentiate search terms, but we shouldn't expect it.  For instance:

User's tags:
-mozilla
-schrep
-mozilla schrep
-work
-schrep work

Query: mozilla schrep work
Result: matches all 5 tags

Query: mozilla, schrep, work
Result: matches 3 of 5 tags

Query: "mozilla schrep" work
Result: matches 2 of 5 tags

moving to m10
moving to m10
Target Milestone: Firefox 3 M9 → Firefox 3 M10
Priority: -- → P1
Seth, are we only planning to handle 'multiple tags' in auto-complete or will this also include handling 'multiple words' search (See Bug #401869 filed by me), where words could be title, url, tags etc. We can dupe my bug if the scope of this bug is all inclusive in its scope.
Attached patch patch (obsolete) — Splinter Review
todo:

1)  the code that converts a search string ("a b c d") into the array of search tokens ("a","b","c","d","a b","b c","c d","a b c","b c d","a b c d") should be moved out, as I'm sure we're going to need that for bug #395462 (handle multple tags for organizer search), and if we do something similar for url title search.

2) when I search on "a b c d e f g h i", I start to get assertions like:

###!!! ASSERTION: LIKE string must not be null!: '!B.IsEmpty()', file /Users/sspitzer/Desktop/trunk/mozilla/storage/src/mozStorageUnicodeFunctions.cpp, line 196.

I might be generating a SQL statement that is too long or that has too many parameters.  (need to debug)

3)  it might be worth storing the two tag statement (like "a" or like "b" or like "a b") as well as the three tag statement (like "a" or like "b" or like "a b" or like "b c" or like "a b c") and only dynamically generating the query if we have more than three tokens.  this statement will get generated when typing in the url bar, so we would benefit from caching it.
actually, unless/until we decide to implement bug #401660 ("when showing autocomplete result, show tags that partially match"), we are doing exact matches on tags.


I'm not sure why I did that (used LIKE) for bug #395267.

the LIKE '?x' ESCAPE '/' syntax comes from the url / title contains autocomplete searches, and really should be an exact match (which will be faster.)

for the organizer search, we (dietrich) appear to be doing the right thing:

 890 dietrich     1.176   // mDBURIHasTag
 891                      rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
 892                          "SELECT b.id FROM moz_bookmarks b "
 893                          "JOIN moz_places p ON b.fk = p.id "
 894                          "WHERE p.url = ?1 "
 895                            "AND (SELECT b1.parent FROM moz_bookmarks b1 WHERE "
 896                            "b1.id = b.parent AND LOWER(b1.title) = LOWER(?2)) = ?3 "
 897                          "LIMIT 1"),
 898                        getter_AddRefs(mDBURIHasTag));
 899                      NS_ENSURE_SUCCESS(rv, rv);

I need to do something similar to that, instead of using LIKE.
switching to using LOWER() is the way to go.

to avoid generating a sql query that is too long or that has too many parameters, I'm going to break up the query in chunks of 12 ("a b c d" -> 12 combinations).

that way, if the user types in a very long sentence into the url (knowing that it will result in a google query), we won't crash.
"a b c d" -> 10, not 12
breaking into chunks has issues, as want to order (among tags) by visit count then visit date, so having multiple queries would mean post-processing the results.

at some point (at 30 tokens), we have a query of ~16k characters and less than the limit of 500 parameters.

after that point, CreateStatement() wil fail, but I think that's acceptable.

updated patch coming.
> and less than the limit of 500 parameters.

that's not the limit we are hitting (which I think is 999 by default), it's that the expression tree is too large (maximum depth 1000).

http://www.sqlite.org/limits.html
Attached patch updated patch (obsolete) — Splinter Review
Attachment #288461 - Attachment is obsolete: true
Attached patch patch (obsolete) — Splinter Review
Attachment #288754 - Attachment is obsolete: true
Attachment #288802 - Flags: review?(dietrich)
Blocks: 403847, 403849
Whiteboard: [includes the fix for bug #395462, #403847, and #403849]
Attachment #288802 - Attachment is obsolete: true
Attachment #288803 - Flags: review?(dietrich)
Attachment #288802 - Flags: review?(dietrich)
Attached patch add comment, clean up code (obsolete) — Splinter Review
Attachment #288803 - Attachment is obsolete: true
Attachment #288804 - Flags: review?(dietrich)
Attachment #288803 - Flags: review?(dietrich)
Comment on attachment 288804 [details] [diff] [review]
add comment, clean up code


>Index: toolkit/components/places/src/nsNavHistory.cpp
>===================================================================
>RCS file: /cvsroot/mozilla/toolkit/components/places/src/nsNavHistory.cpp,v
>retrieving revision 1.189
>diff -p -8 -u -r1.189 nsNavHistory.cpp
>--- toolkit/components/places/src/nsNavHistory.cpp	9 Nov 2007 21:05:49 -0000	1.189
>+++ toolkit/components/places/src/nsNavHistory.cpp	15 Nov 2007 07:37:52 -0000

>@@ -4243,16 +4240,43 @@ nsNavHistory::URIHasTag(nsIURI* aURI, co
>   NS_ENSURE_SUCCESS(rv, rv);
> 
>   PRBool hasTag = PR_FALSE;
>   rv = mDBURIHasTag->ExecuteStep(&hasTag);
>   NS_ENSURE_SUCCESS(rv, rv);
>   return hasTag;
> }
> 
>+PRBool
>+nsNavHistory::URIHasAnyTagFromTokens(const nsACString& aURISpec, const nsStringArray& aTagTokens)
>+{
>+  PRUint32 tagTokensCount = aTagTokens.Count();
>+
>+  // from our tokens, build up all possible tags
>+  // for example:  ("a b c") -> ("a","b","c","a b","b c","a b c")
>+  for (PRUint32 numCon = 1; numCon <= tagTokensCount; numCon++) {
>+    for (PRUint32 i = 0; i < tagTokensCount; i++) {
>+      if (i + numCon > tagTokensCount)
>+        continue;
>+
>+      nsAutoString currentValue;
>+      for (PRUint32 j = i; j < i + numCon; j++) {
>+        if (!currentValue.IsEmpty())
>+          currentValue += NS_LITERAL_STRING(" ");
>+        currentValue += *(aTagTokens.StringAt(j));
>+      }
>+
>+      // if this URI has current tag value, we can stop searching
>+      if (URIHasTag(aURISpec, currentValue))
>+        return PR_TRUE;
>+    }
>+  }
>+
>+  return PR_FALSE;
>+}

This could result in a huge number of queries. Why not use the same generated query as you did for autocomplete?

>@@ -119,17 +120,17 @@ nsNavHistory::CreateAutoCompleteQueries(
> 
>   sql = NS_LITERAL_CSTRING(
>     "SELECT h.url, h.title, f.url, b.id, b.parent "
>     "FROM moz_places h "
>     "JOIN moz_bookmarks b ON b.fk = h.id "
>     "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
>     "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
>     "WHERE "
>-    "(b.parent = (SELECT t.id FROM moz_bookmarks t WHERE t.parent = ?1 and t.title LIKE ?2 ESCAPE '/')) "
>+    "(b.parent = (SELECT t.id FROM moz_bookmarks t WHERE t.parent = ?1 AND LOWER (t.title) = LOWER(?2))) "

nit: space after the first LOWER

>@@ -483,54 +484,146 @@ nsresult nsNavHistory::AutoCompleteTyped

>+  else {
>+    // add in the last match (if it is non-empty)
>+    nsAutoString lastMatch(Substring(strStart, strEnd));
>+    lastMatch.Trim("\r\n\t\b");
>+    if (!lastMatch.IsEmpty())
>+      tagTokens.AppendElement(lastMatch);
>+
>+    PRUint32 tagTokensCount = tagTokens.Length();
>+    // from our tokens, build up all possible tags
>+    // for example:  ("a b c") -> ("a","b","c","a b","b c","a b c")
>+    for (PRUint32 numCon = 1; numCon <= tagTokensCount; numCon++) {
>+      for (PRUint32 i = 0; i < tagTokensCount; i++) {
>+        if (i + numCon > tagTokensCount)
>+          continue;
>+
>+        nsAutoString currentValue;
>+        for (PRUint32 j = i; j < i + numCon; j++) {
>+          if (!currentValue.IsEmpty())
>+            currentValue += NS_LITERAL_STRING(" ");
>+          currentValue += tagTokens[j];
>+        }
>+   
>+        toSearch.AppendElement(currentValue);
>+      }  

nit: whitespace in a few places above.

This looks like duplicate logic from URIHasAnyTagFromTokens(), maybe should make a separate method for that, since it could be used for title/url search also?

>+    }
>+
>+    nsCString tagQuery = NS_LITERAL_CSTRING(
>+      "SELECT h.url, h.title, f.url, b.id, b.parent "
>+      "FROM moz_places h "
>+      "JOIN moz_bookmarks b ON b.fk = h.id "
>+      "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
>+      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
>+      "WHERE "
>+      "(b.parent in "
>+      " (SELECT t.id FROM moz_bookmarks t WHERE t.parent = ?1 AND (");
>+
>+    for (PRUint32 k=0; k<toSearch.Length(); k++) {
>+      if (k)
>+        tagQuery += NS_LITERAL_CSTRING(" OR");
>+
>+      // k+2 to skip over the "?1", which is the tag root parameter
>+      tagQuery += NS_LITERAL_CSTRING(" LOWER(t.title) = ") +
>+                  nsPrintfCString("LOWER(?%d)", k+2);
>+    }
>+
>+    tagQuery += NS_LITERAL_CSTRING("))) "
>+      "GROUP BY h.id ORDER BY h.visit_count DESC, MAX(v.visit_date) DESC;");

Both autocomplete and regular search could be sharing this code, right?

>+
>+    // after 30 tokens, we generate a query with an expression tree that is
>+    // too large.  (by default, the maximum depth is 1000).  at this point
>+    // CreateStatement() will fail.
>+    rv = mDBConn->CreateStatement(tagQuery, getter_AddRefs(tagAutoCompleteQuery));
>+    if (NS_FAILED(rv)) {
>+      NS_WARNING("failed to create the query to find matching tags");
>+      // fail gracefully, so that even though we can't search tags, we can do
>+      // autocomplete search on title and url
>+      return NS_OK;
>+    }

Why search zero tags in this case? And why even bother attempting to create the statement when we know it's going to fail?

It seems like it'd be better to stop accumulating search string combinations when we know it'll fail, and search on the tag combinations generated up to that point.
dietrich, thanks for the review.

> This could result in a huge number of queries. Why not use the same generated
> query as you did for autocomplete?

Note, in this case, we are searching bookmarks, so it's not the same query.

You are right, we are going to generate a lot of queries.  

I'll do something similar to what I'm doing for autocomplete, which is generate one query, with many terms.

I'll move the code that generates the combinations of tokens into a method to that I can re-use it.

> Why search zero tags in this case? And why even bother attempting to create the
> statement when we know it's going to fail?
>
> It seems like it'd be better to stop accumulating search string combinations
> when we know it'll fail, and search on the tag combinations generated up to
> that point.

Yes, I could stop at 30.  that assumes that the SQLITE_MAX_EXPR_DEPTH is 1000.

this limit can change if we recompile sqlite with different options.
Attached patch updated patch (obsolete) — Splinter Review
Attachment #288804 - Attachment is obsolete: true
Attachment #288804 - Flags: review?(dietrich)
Attached patch updated patch (obsolete) — Splinter Review
Attachment #289368 - Attachment is obsolete: true
1)  

This could result in a huge number of queries. Why not use the same generated query as you did for autocomplete?

fixed.  I've kept the cached query, for the common case (one term).

2) 

>+    "(b.parent = (SELECT t.id FROM moz_bookmarks t WHERE t.parent = ?1 AND LOWER (t.title) = LOWER(?2))) "

nit: space after the first LOWER

fixed, thanks.

3)

nit: whitespace in a few places above.

Sorry, I'm not seeing the nits.  Can you elaborate?

4)

This looks like duplicate logic from URIHasAnyTagFromTokens(), maybe should
make a separate method for that, since it could be used for title/url search
also?

Fixed, the common code is in CreateTermsFromTokens()

5)

>+    }
>+
>+    nsCString tagQuery = NS_LITERAL_CSTRING(
>+      "SELECT h.url, h.title, f.url, b.id, b.parent "
>+      "FROM moz_places h "
>+      "JOIN moz_bookmarks b ON b.fk = h.id "
>+      "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
>+      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
>+      "WHERE "
>+      "(b.parent in "
>+      " (SELECT t.id FROM moz_bookmarks t WHERE t.parent = ?1 AND (");
>+
>+    for (PRUint32 k=0; k<toSearch.Length(); k++) {
>+      if (k)
>+        tagQuery += NS_LITERAL_CSTRING(" OR");
>+
>+      // k+2 to skip over the "?1", which is the tag root parameter
>+      tagQuery += NS_LITERAL_CSTRING(" LOWER(t.title) = ") +
>+                  nsPrintfCString("LOWER(?%d)", k+2);
>+    }
>+
>+    tagQuery += NS_LITERAL_CSTRING("))) "
>+      "GROUP BY h.id ORDER BY h.visit_count DESC, MAX(v.visit_date) DESC;");

> Both autocomplete and regular search could be sharing this code, right?

While the "LOWER(t.title) = LOWER(?2) OR LOWER(t.title) = LOWER(?3) OR LOWER(t.title) = LOWER(?4)..."   terms are similar, but the queries are different.

6)

>+    // after 30 tokens, we generate a query with an expression tree that is
>+    // too large.  (by default, the maximum depth is 1000).  at this point
>+    // CreateStatement() will fail.
>+    rv = mDBConn->CreateStatement(tagQuery, getter_AddRefs(tagAutoCompleteQuery));
>+    if (NS_FAILED(rv)) {
>+      NS_WARNING("failed to create the query to find matching tags");
>+      // fail gracefully, so that even though we can't search tags, we can do
>+      // autocomplete search on title and url
>+      return NS_OK;
>+    }

> Why search zero tags in this case? And why even bother attempting to create the
> statement when we know it's going to fail?
>
> It seems like it'd be better to stop accumulating search string combinations
> when we know it'll fail, and search on the tag combinations generated up to
> that point.

I'm still not sure what would be best.  I'd rather not assume 30, as that makes assumptions about the query and that SQLITE_MAX_EXPR_DEPTH is 1000 (the default).

suggestions?
(In reply to comment #26)
> 3)
> 
> nit: whitespace in a few places above.
> 
> Sorry, I'm not seeing the nits.  Can you elaborate?

> >+        nsAutoString currentValue;
> >+        for (PRUint32 j = i; j < i + numCon; j++) {
> >+          if (!currentValue.IsEmpty())
> >+            currentValue += NS_LITERAL_STRING(" ");
> >+          currentValue += tagTokens[j];
> >+        }
> >+   <--
> >+        toSearch.AppendElement(currentValue);
> >+      }  <--
our limit is 30 tokens, or 465 terms.  after that, we fail.

so I'm doing what dietrich suggested over irc which is to stop when we've hit our limit, warn to the console, but do our best to search for the first 465 terms we've generated.
Attachment #289374 - Attachment is obsolete: true
Attachment #289386 - Flags: review?(dietrich)
Attachment #289386 - Attachment is obsolete: true
Attachment #289386 - Flags: review?(dietrich)
Attachment #289402 - Flags: review?(dietrich)
Comment on attachment 289402 [details] [diff] [review]
move call to create terms from tokens out of inner loop

looks ok, r=me. however, please add automated tests. the lack of tests for places autocomplete is already uncomfortable. adding on more features this late in the game increases the cost of regressions.
Attachment #289402 - Flags: review?(dietrich) → review+
I'll write some automated tests for both multiple word tags in bookmarks search and for autocomplete.  you are right, we need some autocomplete tests.

I'm also updating my patch to work with the trunk (after mano's changes).
Attached patch updated to trunk (obsolete) — Splinter Review
Attachment #289402 - Attachment is obsolete: true
Attachment #289608 - Attachment is obsolete: true
Attachment #289609 - Flags: review?(dietrich)
Attachment #289608 - Flags: review?(dietrich)
Attachment #289609 - Flags: review?(dietrich) → review+
Attachment #289601 - Attachment is obsolete: true
Attachment #289609 - Attachment is obsolete: true
Attachment #289710 - Flags: review?(dietrich)
Whiteboard: [includes the fix for bug #395462, #403847, and #403849] → [has patch][need review dietrich][includes the fix for bug #395462, #403847, and #403849]
Comment on attachment 289710 [details] [diff] [review]
include test for testing history autocomplete search with tags

r=me. thanks very much for adding autocomplete tests.
Attachment #289710 - Flags: review?(dietrich) → review+
fixed.

Checking in src/nsNavHistory.cpp;
/cvsroot/mozilla/toolkit/components/places/src/nsNavHistory.cpp,v  <--  nsNavHistory.cpp
new revision: 1.197; previous revision: 1.196
done
Checking in src/nsNavHistory.h;
/cvsroot/mozilla/toolkit/components/places/src/nsNavHistory.h,v  <--  nsNavHistory.h
new revision: 1.114; previous revision: 1.113
done
Checking in src/nsNavHistoryAutoComplete.cpp;
/cvsroot/mozilla/toolkit/components/places/src/nsNavHistoryAutoComplete.cpp,v  <--  nsNavHistoryAutoComplete.cpp
new revision: 1.26; previous revision: 1.25
done
RCS file: /cvsroot/mozilla/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js,v
done
Checking in tests/unit/test_history_autocomplete_tags.js;
/cvsroot/mozilla/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js,v  <--  test_history_autocomplete_tags.js
initial revision: 1.1
done
RCS file: /cvsroot/mozilla/toolkit/components/places/tests/unit/test_multi_word_tags.js,v
done
Checking in tests/unit/test_multi_word_tags.js;
/cvsroot/mozilla/toolkit/components/places/tests/unit/test_multi_word_tags.js,v  <--  test_multi_word_tags.js
initial revision: 1.1
done
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Whiteboard: [has patch][need review dietrich][includes the fix for bug #395462, #403847, and #403849]
Flags: in-testsuite+
So what about this:

(In reply to comment #3)
> Is there a seperate bug for matching multiple terms against page titles and
> addresses, or would this apply to that as well?
> Is there a seperate bug for matching multiple terms against page titles and
> addresses, or would this apply to that as well?

dao / beltzner:  let's let bug #401869 cover this issue.

additionally, I've logged spin off bug #405316 about supporting quotes and
commas (from comment #3 and comment #5 of this bug)
verified with Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9b2pre) Gecko/2007112604 Minefield/3.0b2pre
Status: RESOLVED → VERIFIED
When I enter multiple tags to search (be it in the location bar, bookmarks sidebar or the newly named library), I get as a result all bookmarks that contain at least one of the tags I entered. Is that the expected behavior?

I thought that when one types multiple words for a search one is trying to narrow down the results to those which contain all of that words. At least I am.

I'm using Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b3pre) Gecko/2007122605 Minefield/3.0b3pre.
>I thought that when one types multiple words for a search one is trying to
>narrow down the results

I agree that multiple tags should narrow the results.
> I agree that multiple tags should narrow the results.

From earlier comments in this bug, specifically comment #5, I thought we wanted multiple words to do an OR search, which would increase the results.

We could change that to be AND, which would mean that more tags would narrow the results.

faaborg, can you confirm that you want this change?
(In reply to comment #44)
> > I agree that multiple tags should narrow the results.
> 
> From earlier comments in this bug, specifically comment #5, I thought we wanted
> multiple words to do an OR search, which would increase the results.
> 
> We could change that to be AND, which would mean that more tags would narrow
> the results.
> 
> faaborg, can you confirm that you want this change?
> 

Seth, wasn't OR search in scope of Bug #401869 ?
>From earlier comments in this bug, specifically comment #5, I thought we wanted
>multiple words to do an OR search, which would increase the results.

Shoot, I totally forgot about the syntax problem (the earlier comments were about if users were expected to use any special syntax when they enter results).  To clarify, the behavior I think makes the most sense is probably going to be a little harder to implement.  I think we should match a tag if the user enters any full word in the tag, but tag hits should function as an AND operation and limit results.  This behavior is based on the two assumptions:

-users have messy and redundant tag sets
-search based faceted browsing is a very powerful way to drill down to the results you want

Here are some examples of the behavior I'm talking about

Tag set:

Scuba
Vacation
Vacation Hotels
Hotels
Island

Search: "Scuba Island" = (Scuba) AND (Island)

Search: "Scuba Hotels" = (Scuba) AND ((Hotels) OR (Vacation Hotels))

Search: "Island Scuba Vacation" = (Island) AND (Scuba) AND ((Vacation) OR (Vacation Hotels))

Search: "Island Scuba Vacation Hotels" = (Island) AND (Scuba) AND ((Vacation) OR (Vacation Hotels)) AND ((Hotels) OR (Vacation Hotels))

One big caveat is that we should only start doing AND operations on the results if the start of the search query matches a complete tag.  Otherwise I'm pretty sure that with a large tag set, nearly any query would begin to kick off AND searches that filter to nothing.

Also, if we want to add support for commas and quotes so advanced users can enter unambiguous queries, that would be great but shouldn't be our top priority.
(In reply to comment #46)
> 
> Tag set:
> 
> Scuba
> Vacation
> Vacation Hotels
> Hotels
> Island
> 
> Search: "Scuba Island" = (Scuba) AND (Island)
> 
> Search: "Scuba Hotels" = (Scuba) AND ((Hotels) OR (Vacation Hotels))
> 
> Search: "Island Scuba Vacation" = (Island) AND (Scuba) AND ((Vacation) OR
> (Vacation Hotels))
> 
> Search: "Island Scuba Vacation Hotels" = (Island) AND (Scuba) AND ((Vacation)
> OR (Vacation Hotels)) AND ((Hotels) OR (Vacation Hotels))
> 

That's my thinking, except for the partial multiple worlds tag matching, since, nowadays, it's not working. So, without altering that, primarily changing the way it is now to the narrower behavior would result in:

Search: "Scuba Hotels" = (Scuba) AND (Hotels)

Search: "Island Scuba Vacation" = (Island) AND (Scuba) AND (Vacation)

The other two would be the same.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: