Problem/Motivation
In Drupal 8 the view search filter (Drupal\search\Plugin\views\filter\Search) is using a LIKE statement on the search_dataset table.
.. AND ((node_search_index.type = 'node_search') AND (node_search_dataset.data LIKE '% example %' ESCAPE '\') AND (node_search_dataset.data LIKE '% other %' ESCAPE '\'))
When it should be searching for each word in the search_index table.
AND ( (node_search_index.type = 'node_search') AND ( (node_search_index.word = 'example') OR (node_search_index.word = 'other') )
- Clean installation of D8
- Create a page titled 'Testing one two two two two' (node/add/page)
- Create a page titled 'Testing one one one' (node/add/page)
- Run cron task manually. (admin/reports/status)
- Verify search index is at 100% (admin/config/search/pages)
- Add search score field, keys filter, and score sort DESC to content view (admin/structure/views/view/content)
- Execute a few search and notice how the score never changes.
- admin/content?keys=testing
- admin/content?keys=one
- admin/content?keys=two
- Also note how 'Testing one two two two two' appear first when searching for 'one'.
The updated content view is attached.
Proposed resolution
The root problem is that the Views queries created by the Search filter/argument plugins are missing WHERE clauses. See comments #3 and #4 for explanation.
So the solution is to add those WHERE clauses into the Views queries.
Remaining tasks
Make a patch, with tests.
[Tests are still To Do]
User interface changes
Search filters in Views will work better.
API changes
None.
Data model changes
None.
Beta phase evaluation
Comments
Comment #1
jhodgdonAs a note, when you create this content and use the main Search box to search, you get the right results. If you search for "one", the Testing one one one node comes up first. So this problem seems to be specific to Views. I'll take a look...
Comment #2
jhodgdonInterestingly, I am only seeing this problem when I make Page nodes with empty bodies. I first tested by creating Article nodes with a body of "This is a test" and I did not see this problem. But once I created Page nodes with empty body, I could see this problem. But still both my articles and my pages are working correctly outside Views in a normal content search.
So let's see what the difference is in the queries. When I search for "one" in the views preview area, Views is telling me the query is:
I added a drupal_set_message to the SearchQuery class to show me the query on the Search page, and that is showing:
Very odd. I do not see a huge difference in those queries. It looks like the ORDER BY is the same, plus or minus using different table aliases in the two queries.
Comment #3
jhodgdonOh wait. The views query has
And the SearchQuery query has
So that is the difference. The views query is not filtering the search_index table down to the right word, when it is adding up the scores. That is a bug.
Explanation: The search_index table keeps track of all the words found in the node, and assigns each one a score for that node. If you don't filter the scores based on the words in the actual query, you're basically asking "What is the total score of this node" not "What is the total score for the words I am searching on in this node".
So the relevance score is not working right for Views. We need to fix this in the Search filter and Search argument plugins for Views. And add more tests for them most likely.
Comment #4
jhodgdonThe problem here is that the Views plugins are calling SearchQuery::parseSearchExpression() and assuming that the search query is fully set up with conditions, that the Views plugins then add to the query.
But the i.word conditions are not added at that point, so they are not added to the Views queries. Those are added in the prepareAndNormalize() method, which the Views queries don't want to deal with and shouldn't, because that assumes different search rankings as set up on the search plugin, and Views only offers relevance. But it needs the i.word expressions.
Here's a patch that fixes the problem. Probably needs a test.
Comment #5
jhodgdonAs a note there is a small docs fix that is technically unrelated to the issue here in the patch. We can move it to another issue, but I ran into the docs being wrong when exploring solutions to the issue so it got left in.
Oops I forgot the patch.
Comment #6
jhodgdonSpun the docs part from ViewsSearchQuery into its own issue.
#2544870: Docs problem on ViewsSearchQuery::conditionReplaceString() so that part should be removed from this patch. Since this patch still needs tests I'll wait.
Comment #7
jhodgdonSummary update
Comment #8
jhedstromConfirmed this patch resolves the issue via manual testing. I may have some time later today to write a test.
Comment #9
jhodgdonRegarding tests, we have SearchRankingTest in the Search module, which tests ranking for the main search functionality. This is more complex than the behavior in Views, because the main search page offers configurable ranking (you can set all kinds of factors, not just search keyword relevance).
That test makes a node whose body is "Drupal's search rocks", and then another one that says "Drupal's search rocks really rocks", and it verifies that the order is right if you search for "rocks" (i.e., that it's "rocks rocks" before "rocks").
The other test we have is in the Views module, SearchIntegrationTest, which tests the search filter and argument plugins.
So... I think the thing to do would be to add to SearchIntegrationTest. We should make nodes similar to the ones used to test relevant rankings in SearchRankingTest, and verify that they appear in the right order when searching via the test-filter and test-arg views that are set up in SearchIntegrationTest.
If you want to right a test, @jhedstrom, please do! That would be my suggestion of how to do it. Of course, attaching a test-only patch to verify that it fails would be ideal. :)
Comment #10
jhodgdonCome to think of it, we should consider adding to both SearchRankingTest and SearchIntegrationTest the exact test strings you came up with in this test, because some variations do not exhibit the problem.
Comment #11
jhedstromThis adds to sorting tests to
SearchIntegrationTest, but I was just wrapping up, so this doesn't changeSearchRankingTest.Comment #14
jhedstromThat's what I get for adding to the test when testing the test-only bit :)
Comment #16
jhodgdonInteresting. It looks like the "one two two"/"one one one" test is the better one for this bug.
We need to take this bit out of the patch (I moved it to a different issue).
Other than that, looks great! So I'll just edit the patch and take that file's section out. (Oh, the horror!). Attached patch is the same as #14 but without ViewsSearchQuery.
I hereby pronounce the test part of the patch RTBC. I cannot RTBC the code part of the patch as I wrote it.
Comment #17
jhedstromI'm RTBC'ing the code part of the change, as it works as expected in both manual and automated testing.
Comment #18
alexpottThis issue is a normal bug fix, and doesn't include any disruptive changes, so it is allowed per https://www.drupal.org/core/beta-changes. Committed 7e4c9d7 and pushed to 8.0.x. Thanks!
Tested on postgres as well cause views sorting can be different - test passes.