Re: Towards faster keyword searches

Jeff Fearn <[email protected]> Mon, 26 Sep 2016 13:51:38 +1000
Newsgroups gmane.comp.bug-tracking.bugzilla.devel
Message-ID <[email protected]>
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--SL2H6irt455o2Q8LJHhhhFMTAIhc2xHdT
From: Jeff Fearn <[email protected]>
To: [email protected]
Message-ID: <fa99a66e-293e-9c13-2d47-3d7e3f8b36d4-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Subject: Re: Towards faster keyword searches
References: <D821D042-2A15-424B-94EF-15A4121764C4-4eJtQOnFJqFBDgjK7y7TUQ@public.gmane.org>
In-Reply-To: <D821D042-2A15-424B-94EF-15A4121764C4-4eJtQOnFJqFBDgjK7y7TUQ@public.gmane.org>
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

On 26/09/2016 12:46, Dylan Hardison wrote:
> When you have a keyword on 50,000+ bugs it means you're building a sql qu=
ery with a 50,000 list in the form of IN (50,000 ids).
> This is gets close to the limits mysql has on queries, at least and it's =
pretty slow.

Not only that, when you get to 65K you hit parameter limits in DBD::Pg :(

I've just had to fix a bug for this related to viewing bugs in a group.
I solved it by replacing the use of new_from_list with new_from_where
which takes the SQL used to generate the bug id list and uses it in the
query.

https://jfearn.fedorapeople.org/65KBugsInAGroup.patch

I'm not very happy with it because it requires you knowing exactly how
the sql will be used and coupling is bad, mmmk.

A more general approach to doing sub-selects instead of ID lists would
be great.

> There are a whole class of these -- anything that is a 'multiselect' type=
 search. I believe someone suggested embedding these queries (at least as a=
n option)
> as a sub select and in general I think that's a good idea. An even nicer =
idea is to just let elastic search do the searching.
> One of these approaches I hope to explore with an outreachy intern.

The effect of using ID lists instead of sub selects is wider than just
searching, as the above patch demonstrates.

> However, for the moment I really need keyword searches to be fast, so I s=
tarted looking at the search code[1].
> I started at the problem backwards -- first by looking at where we build =
search objects (the tree-like Bugzilla::Search::Clause::* stuff).
> For searches with a single keyword search, I thought it would be nice to =
turn that into a join.
>=20
> Then I wrote that, and it appears the code I wrote actually works general=
ly for multiple keywords (although you then start wondering what the max nu=
mber of joins is.)
>=20
> Anyway, it's not finished code but it does work on a test install.
>=20
> It's in a github branch: https://github.com/dylanwh/bugzilla/tree/fast-ke=
ywords,
> you can look at the diff here: https://github.com/dylanwh/bugzilla/commit=
/e88bdf7168c6723d9930bc771ea93c93c3dec6b0
>=20
> I will be polishing this up for a review, but I wanted to have other peop=
le look at it first.
>=20
> Here's an example of a query it builds, for single_keyword=3Dbatman AND s=
ingle_keyword:frog
>=20
> SELECT bugs.bug_id AS bug_id, bugs.priority AS priority, bugs.bug_severit=
y AS bug_severity
>   FROM bugs
> LEFT JOIN bug_group_map AS security_map ON bugs.bug_id =3D security_map.b=
ug_id
> LEFT JOIN cc AS security_cc ON bugs.bug_id =3D security_cc.bug_id AND sec=
urity_cc.who =3D 1
> INNER JOIN priority AS map_priority ON bugs.priority =3D map_priority.val=
ue
> INNER JOIN bug_severity AS map_bug_severity ON bugs.bug_severity =3D map_=
bug_severity.value
> LEFT JOIN keywords AS keywords_1 ON bugs.bug_id =3D keywords_1.bug_id
> LEFT JOIN keyworddefs AS keyworddefs_1 ON keywords_1.keywordid =3D keywor=
ddefs_1.id
> LEFT JOIN keywords AS keywords_2 ON bugs.bug_id =3D keywords_2.bug_id
> LEFT JOIN keyworddefs AS keyworddefs_2 ON keywords_2.keywordid =3D keywor=
ddefs_2.id
>  WHERE bugs.creation_ts IS NOT NULL
>    AND ( (security_map.group_id IS NULL OR security_map.group_id IN (1,10=
,11,14,12,13,9,4,8,5,6,7,3,2))
>         OR (bugs.reporter_accessible =3D 1 AND bugs.reporter =3D 1)
>         OR (bugs.cclist_accessible =3D 1 AND security_cc.who IS NOT NULL)
>         OR bugs.assigned_to =3D 1
> )
>    AND  bugs.resolution IN ('')  AND keyworddefs_1.name =3D 'batman' AND =
INSTR(keyworddefs_2.name, 'frog') =3D 0
> GROUP BY bugs.bug_id
> ORDER BY map_priority.sortkey, map_priority.value, map_bug_severity.sortk=
ey, map_bug_severity.value
> LIMIT 500-
> To view or change your list settings, click here:
> <https://lists.bugzilla.org/cgi-bin/[email protected]>
>=20

I ran this on a copy of our DB and it seems to perform well. I did have
to chop off the order by as it's not leagl in Pg to have a group by
clause and then order by things not in the group by clause or an
aggregate function.

Cheers, Jeff.




--SL2H6irt455o2Q8LJHhhhFMTAIhc2xHdT
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJX6JtKAAoJELs3R4zxGZvK6nEH/jiy32muaXj0Xmexy48WjOBY
CoDaMNFKQph4XGTnScmO9m/mzjIZZCybkkTwCrcV9ySHrFSDhHAs/WpzUu8eXzlM
9ibqX3vfmLCkAJyEqdkzAU1J2hxh/UItqKeGUjy63D2JDqbwmBM545Ouh3SGTX+T
+Ykmeo/IOzQebK52lSpv9pJmlEP9l+MdGlyOJD6bF6yLCr6GQd/zc8drXBB4Bwtm
ZYoftpwjcTSGMXuwR7JOVU1wUiQ4LXbuMCzmngGtN4vhOpPDDKQF9LY/MiV7T1Qt
XVjqrjloCkFHrZoVLKHHur3wPm0nD6VjBAd7b21Op7bjgb38B9iPm87pyxrAM4c=
=wDUp
-----END PGP SIGNATURE-----

--SL2H6irt455o2Q8LJHhhhFMTAIhc2xHdT--