2014년 12월 4일 목요일

Full-text search using indexes as well as id

We have a full-text index created, and we are using PHP on the server side.

We'd like the search to use the full-text indexes as well as the id field, so users can either type free form text, or an ID of a document. Is this possible? Currently we are running the following PHP code:

return $mongo_db->command(array(
   "text" => $mongo_collection->getName(),
   "search" => $search_string,
   "limit" => 25
));



In MongoDB 2.6 and later, you should be able to do this:

$cursor = $mongo_collection->find(
        [ '$or' => [
                [ '_id' => $search_string ],
                [ '$text' => [ '$search' => $search_string ] ]
        ] ]
)->limit( 25 );

return iterator_to_array( $cursor );

There is no need to use a command any longer, as text search has been
integrated into the querying system. See also:
http://docs.mongodb.org/manual/reference/operator/query/text/#op._S_text



Are you sure the official PHP driver (http://php.net/manual/en/book.mongo.php) supports this? I am first just trying to use find with a text index, but the result cursor is always empty.

            return $mongo_collection->find(array(
                '$text' => array(
                    '$search' => $search_string
                )
            ))->limit($limit);

According to the documentation you have to use command like I was:




> Are you sure the official PHP driver
> (http://php.net/manual/en/book.mongo.php) supports this?
The PHP driver itself does not need to have support for it, as it just
sends the find() or command() arguments directly to the server anyway.

> I am first just trying to use find with a text index, but the result
> cursor is always empty.
>
>             return $mongo_collection->find(array(
>                 '$text' => array(
>                     '$search' => $search_string
>                 )
>             ))->limit($limit);
That doesn't quite do the same. That returns a MongoCursor object, just
like a normal find would do, and not an array.

That's why I used the iterator_to_array() method before the return.

> According to the documentation you have to use command like I was:
>
http://php.net/manual/en/mongodb.command.php
I tested it of course, and it worked for me :-) See attached file.

The *deprecated* way is to use text search through the command, and that
also still works.

test-results.txt



Using the find() method it appears the score property is not returned any longer. How can I get the full-text score returned? Also, are the results ordered by score desc?

           $cursor = $mongo_collection::find(
                    [ '$text' => [ '$search' => $search_string ]]
            )->limit($limit);

            return iterator_to_array($cursor);



> Using the find() method it appears the score property is not returned
> any longer. How can I get the full-text score returned? Also, are the
> results ordered by score desc?
>
>            $cursor = $mongo_collection::find(
>                     [ '$text' => [ '$search' => $search_string ]]
>             )->limit($limit);
>
>             return iterator_to_array($cursor);
The documentation that I linked to earlier explains that. A direct link
to that section is
http://docs.mongodb.org/manual/reference/operator/query/text/#return-the-text-search-score

In short, you can do that in the projection. In PHP, you do that like:

        $cursor = $mongo_collection::find(
                [ '$text' => [ '$search' => $search_string ]],
                [ 'score' => [ '$meta' => 'textScore' ] ]
        )->limit($limit);

When you have done a projection with textScore, you can also sort
according to the field as described at
http://docs.mongodb.org/manual/reference/operator/query/text/#return-the-text-search-score

        $cursor = $mongo_collection::find(
                [ '$text' => [ '$search' => $search_string ]],
                [ 'score' => [ '$meta' => 'textScore' ] ]
        )->sort->( [ 'score' => [ '$meta' => 'textScore' ] ] )->limit($limit);

The default sort order does not seem to be by text score, so you will
need to sort according to that yourself.



Thanks for all the help, everything worked, except the limit does not seem to limit the result cursor.

$cursor = MongoConnection::find(
    ['$text' => ['$search' => $search_string]],
    ['score' => ['$meta' => 'textScore']]
)->sort(['score' => ['$meta' => 'textScore']]);
return $cursor->limit(20);

Any ideas?


댓글 없음:

댓글 쓰기