Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend accounts table for custom search attributes #27832

Closed
wants to merge 8 commits into from

Conversation

tomneedham
Copy link
Contributor

@tomneedham tomneedham commented May 8, 2017

Description

  • Adds an additional column to the accounts table that can be supplied by the user backends to permit improved searching
  • Adds a find method to user manager to query email, displayname, userid and search_attributes
  • Adds a findUsersInGroup method to query group backends and filter users using the find method

How Has This Been Tested?

  • Extended the Database user backend to return a string and observed string in database
  • Tested searching for users in the sharee dialog box using their email address

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@tomneedham tomneedham added this to the 10.0.1 milestone May 8, 2017
@tomneedham tomneedham self-assigned this May 8, 2017
@PVince81
Copy link
Contributor

PVince81 commented May 9, 2017

Steps:

  1. Enable guest app
  2. Run npm run build if you picked the guest app and are wondering why it doesn't work
  3. Share a folder "test" with "Someone" and wait for the "(guest)" entry appears in the dropdown, select it
  4. Type in an email address
  5. Save
  6. Log out
  7. Open the email
  8. Open the link from the email
  9. Set a password
  10. Login as admin user again (or whatever first user from step 1)
  11. Create a folder "test2"
  12. Type "Someo" to search for the existing guest user

Expected: guest user appears
Actual: "an error occurred"

{"reqId":"nCeGIVUGZ56IHxxMZ6Zu","level":3,"time":"2017-05-09T16:16:54+00:00","remoteAddr":"127.0.0.1","user":"admin","app":"PHP","method":"GET","url":"\/owncloud\/ocs\/v1.php\/apps\/files_sharing\/api\/v1\/sharees?format=json&search=vince&perPage=200&itemType=folder","message":"Call to undefined method OC\\User\\User::getEmail() at \/srv\/www\/htdocs\/owncloud\/apps\/files_sharing\/lib\/Controller\/ShareesController.php#165"}

@PVince81
Copy link
Contributor

PVince81 commented May 9, 2017

note that in my case the email address also started with "someone". Well, actually I used "Vincent" as guest name and "vincent@hostname.tld" (where hostname.tld is the local computer) when testing. So the bug could also be related to this overlap when searching.

From the error it seems to be an API issue.

@tomneedham
Copy link
Contributor Author

REF: #27850

@@ -46,6 +46,7 @@
const SET_DISPLAYNAME = 1048576; // 1 << 20
const PROVIDE_AVATAR = 16777216; // 1 << 24
const COUNT_USERS = 268435456; // 1 << 28
const SEARCH_STRING = 4294967296; // 1 << 32
Copy link
Member

@butonic butonic May 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we start exceeding max int here ... why are the constants shifted by 4 anyway? wtf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👽

$table->addColumn('searchString', 'string', [
'notnull' => false,
'length' => 64,
]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs an index

@tomneedham tomneedham changed the title Add find methods to user manager and group manager Extend accounts table for custom search attributes May 11, 2017
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->Like('user_id', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter(strtolower($pattern)) . '%')))
->orWhere($qb->expr()->iLike('display_name', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quoting comment from http://stackoverflow.com/a/34029944:

It is in PostgreSQL the keyword ILIKE can be used instead of LIKE to make the match case-insensitive according to the active locale. This is not in the SQL standard but is a PostgreSQL extension.

Copy link
Member

@butonic butonic May 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the question here? We use ILIKE from postgres and have adapters for mysql, sqlite and oracle.

On oracle it is currently problematic when the search string contains [ or ] see #26672

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have hidden magic then it's ok.

foreach($groupUsers as $groupUser) {
$matchingUsers[$groupUser->getUID()] = $groupUser;
}
die(var_dump($matchingUsers));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💣 💥

// Add column to hold additional search attributes
$table->addColumn('search_attributes', 'string', [
'notnull' => false,
'length' => 64,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is far from being enough

@tomneedham tomneedham force-pushed the user-account-find branch 2 times, most recently from 802798c to 80a4a7d Compare May 12, 2017 07:57
]);

// Add index for search attributes
$table->addIndex(['search_attributes'], 'search_attributes_index');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a combined index if one query searches in multiple columns

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomneedham any update ?

Copy link
Member

@butonic butonic May 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope. we need an index per or part of a query:

-- with combined index
CREATE INDEX find_index ON oc_accounts (lower_user_id, display_name, email);
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id LIKE '%test%' and display_name LIKE '%test%' and email LIKE '%test%';
0|0|0|SCAN TABLE oc_accounts
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id LIKE '%test%' or display_name LIKE '%test%' or email LIKE '%test%';
0|0|0|SCAN TABLE oc_accounts
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id LIKE '%test%' or display_name LIKE '%test%' or email LIKE '%test%';
0|0|0|SCAN TABLE oc_accounts
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id = '%test%' or display_name = '%test%' or email = '%test%';
0|0|0|SCAN TABLE oc_accounts
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id = '%test%' and display_name = '%test%' and email = '%test%';
0|0|0|SEARCH TABLE oc_accounts USING INDEX find_index (lower_user_id=? AND display_name=? AND email=?)
sqlite> 

...
-- with individual indexes
CREATE UNIQUE INDEX lower_user_id_index ON oc_accounts (lower_user_id);
CREATE INDEX display_name_index ON oc_accounts (display_name);
CREATE INDEX email_index ON oc_accounts (email);
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id = '%test%' and display_name = '%test%' and email = '%test%';
0|0|0|SEARCH TABLE oc_accounts USING INDEX lower_user_id_index (lower_user_id=?)
sqlite> EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id = '%test%' or display_name = '%test%' or email = '%test%';
0|0|0|SEARCH TABLE oc_accounts USING INDEX lower_user_id_index (lower_user_id=?)
0|0|0|SEARCH TABLE oc_accounts USING INDEX display_name_index (display_name=?)
0|0|0|SEARCH TABLE oc_accounts USING INDEX email_index (email=?)
sqlite> 

then again like kills the indexes on sqlite anyway:

EXPLAIN QUERY PLAN select * from oc_accounts WHERE lower_user_id like '%test%' or display_name like '%test%' or email like '%test%';
0|0|0|SCAN TABLE oc_accounts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh well. the %test% like comparison kills the index on all dbms. If we use test% it is much better:

mysql> explain select * from oc_accounts WHERE lower_user_id like '%test%' or display_name like '%test%' or email like '%test%';
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table       | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | oc_accounts | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+

mysql> explain select * from oc_accounts WHERE lower_user_id like 'test%' or display_name like 'test%' or email like 'test%';
+----+-------------+-------------+------------+------+----------------------------------------------------+------+---------+------+------+----------+-------------+
| id | select_type | table       | partitions | type | possible_keys                                      | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------------+------------+------+----------------------------------------------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | oc_accounts | NULL       | ALL  | lower_user_id_index,display_name_index,email_index | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------------+------------+------+----------------------------------------------------+------+---------+------+------+----------+-------------+

sqlite never seems to use an index for like
mysql can use separate indexes as well as a combined index ... if we don't do medial searches.

for ldap we have 'user_ldap.enable_medial_search' in config.php to allow medial searches. we could do the same for sql. say ... 'accounts.enable_medial_search'?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PVince81
Copy link
Contributor

ok guest app part seems to work again

@PVince81
Copy link
Contributor

With the guest app if I type in the email of the previously created guest user it appears in the list with the display name and I can select it for sharing.

@PVince81
Copy link
Contributor

Fixes #27847

@PVince81
Copy link
Contributor

Apart from the index question, is this ready ? @butonic @DeepDiver1975 @jvillafanez

@cdamken
Copy link
Contributor

cdamken commented May 15, 2017

wait, im testing now :)

@cdamken
Copy link
Contributor

cdamken commented May 15, 2017

Looks good for me now 👍 Tested and works!

@tomneedham
Copy link
Contributor Author

185 for the length of the search_attributes column as according to some research by @butonic this is the max indexable length we can achieve - so my understanding is that if we add an index that spans this column as well it won't be effective

@tomneedham
Copy link
Contributor Author

Working on a new branch / PR - closing for now

@PVince81
Copy link
Contributor

the new PR #27906

@DeepDiver1975 DeepDiver1975 deleted the user-account-find branch August 11, 2017 22:53
@lock
Copy link

lock bot commented Aug 2, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Aug 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants