Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oxMrb-000822-7Q for pgsql-bugs@arkaria.postgresql.org; Tue, 22 Nov 2022 06:34:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oxMra-0007PC-0m for pgsql-bugs@arkaria.postgresql.org; Tue, 22 Nov 2022 06:34:34 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oxMrZ-0007P2-LT for pgsql-bugs@lists.postgresql.org; Tue, 22 Nov 2022 06:34:33 +0000 Received: from mout02.posteo.de ([185.67.36.66]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oxMrW-0006wk-VF for pgsql-bugs@lists.postgresql.org; Tue, 22 Nov 2022 06:34:33 +0000 Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id CCE9A240101 for ; Tue, 22 Nov 2022 07:34:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1669098868; bh=QSRsJx01EjzD7/q6Ywdn0Tr20l72FPPmml+ENZv9A40=; h=Date:From:To:Subject:From; b=rENeCVb60dYFv7YVhc4eQUJIUatE0n24kOkp93LPxBxrEKgpG/r/sifbtqZyXKy92 ur4+wENXP3raGM5113OuahSAyuP442GoqaJmyApd4QzvuQtlcAl7YpgMoZIpoDbPNf V0OL5PJqdIBn0h0wWASMXl4qbPq7hTIoqWlyp5hFg4CK8xN6wMypI8gY05yLVskPPH 5DNvJT13oSJ62Zit/H9sPamaYRvLLMc62i5uB8ZoyDOPE0Tl4Ksa60CDDdB6JbukKH XGx6OtfZkTuDQ3RiVVrDSQVC7gcjGp6h2mOvVkkd2jZ7f4g6v0QSbmUiqu2lRmxRC8 Gr+SN8XR/6TmQ== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4NGZH709qYz6tqn; Tue, 22 Nov 2022 07:34:26 +0100 (CET) Date: Tue, 22 Nov 2022 06:34:21 +0000 From: sebastian.patino-lang@posteo.net To: Tom Lane , pgsql-bugs@lists.postgresql.org Message-ID: <6702b4c1-457f-4e34-a844-bb9cfe4c7e6a@Spark> In-Reply-To: <2885495.1668972591@sss.pgh.pa.us> References: <17691-93cef39a14663963@postgresql.org> <2885495.1668972591@sss.pgh.pa.us> Subject: Re: BUG #17691: Unexpected behaviour using ts_headline() X-Readdle-Message-ID: 6702b4c1-457f-4e34-a844-bb9cfe4c7e6a@Spark MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="637c6d72_3d1b58ba_89ae" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --637c6d72_3d1b58ba_89ae Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi Tom, thanks for the in-depth explanation. Makes a bit more sense now. Not sure what to do with the attached patch though. Should I use that to compile my own version of PG? Since I use a managed version thats not an option currently. Regards Sebastian On 20. Nov 2022, 20:30 +0100, Tom Lane , wrote: > PG Bug reporting form writes: > > I experience unexpected behaviour when using ts_headline() in general, but > > especially when changing MaxFragments. Given the data in > > ts_headline_report.sql [1] > > Thanks for sending the sample data. After poking at this a bit, it > seems the question boils down to what ts_headline should do when there > simply aren't any short matches to the query. Part of the issue there > is what qualifies as "short". The definition I installed in 78e73e875 > was > > + /* > + * We might eventually make max_cover a user-settable parameter, but for > + * now, just compute a reasonable value based on max_words and > + * max_fragments. > + */ > + max_cover = Max(max_words * 10, 100); > + if (max_fragments > 0) > + max_cover *= max_fragments; > > Looking at this again, I think the dependency on max_fragments is just > wrong. That is what is causing your different results for different > settings of MaxFragments: larger values allow recognition of longer > candidate covers ("cover" being jargon in this code for "a substring > satisfying the query"). But there's no good reason for that. I'd misread > the logic in mark_hl_fragments, which "breaks the cover into smaller > fragments such that each fragment has at most max_words", to think that > it needed to see longer covers that it could divide into fragments. > But actually max_fragments limits the number of fragments it will return > across all covers, and there doesn't seem to be a reason to connect that > parameter to the acceptable length of any particular cover. So dropping > those two lines is enough to make the strange behavior across differing > MaxFragments go away. > > The other issue is what to do after finding there's no match of max_cover > or fewer tokens. As the code now stands, it'll just give up and return > the initial bit of the text, likely with no query words. That's not > great. I propose that we look for any match and return (highlight) just > its first word. > > > SELECT id, > > ts_headline('english', "texts"."fulltext", to_tsquery('english', 'amazon & > > world'), 'StartSel=<<, StopSel=>>') AS "preview" > > FROM texts; > > > id=1: Highlight word is the first one in the result. Expectation: highlight > > word is somewhere in the middle. > > Meh --- I don't agree with that expectation. The fragment-based code does > act that way, but the non-fragment path never has, so I think we'd make > more people unhappy than happy if we change its behavior. > > > id=2: No highlight word at all. > > Right, because there are no short matches to "amazon & world" anywhere. > With the attached proposed patch, we'll highlight whichever one of those > words appears first. > > > id=3: Highlight words are the first and last one in the result. Not ideal > > but ok-ish. > > As I said, that's how non-fragment highlighting has always worked. It > will extend the quoted text, but not beyond min_words, which is a bit > different from fragment highlighting. > > > SELECT id, > > ts_headline('english', "texts"."fulltext", to_tsquery('english', 'amazon & > > world'), 'MaxFragments=3, StartSel=<<, StopSel=>>') AS "preview" > > FROM texts; > > > id=1: Wrong number of fragments (2) with highlight words are returned. > > I don't agree with this expectation either. There's only one reasonably > sane match to 'amazon & world' in that text, and it's near the beginning. > As the code stands, increasing max_fragments eventually allows it to find > some less-sane matches, but that doesn't seem like an improvement. > > > In short, I suggest something about like the attached. For your id=2 > example, which has only very far-apart occurrences of 'amazon' and > 'world', this produces > > <> where fast runtimes make or break the popularity of research > fields, this oversight has effectively > > without fragmenting, and > > researchers make the effort of understanding the inner workings of > these convenient black-boxes. In a <> where fast runtimes make > or break the popularity of research fields, this oversight has > effectively surrendered most > > with fragmenting, which is okay by me given their historically different > behaviors. Otherwise, it gets rid of the strange changes in matching > behavior for different MaxFragment values. > > regards, tom lane > --637c6d72_3d1b58ba_89ae Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline
Hi Tom,

thanks for the in-depth explanation. Makes a bit more sense now. Not sure= what to do with the attached patch though. Should I use that to compile = my own version of PG=3F Since I use a managed version thats not an option= currently.

Regards

Sebastian
On 20. Nov 2022, 20:30 +0100, Tom L= ane <tgl=40sss.pgh.pa.us>, wrote:
PG Bug reporting form <noreply=40postgresql.org> writes:<= br />
I experience unexpected behaviour when usin= g ts=5Fheadline() in general, but
especially when changing Max=46ragments. Given the data in
ts=5Fheadline=5Freport.sql =5B1=5D

Thanks for sending the sample data. After poking at this a bit, it
seems the question boils down to what ts=5Fheadline should do when there<= br /> simply aren't any short matches to the query. Part of the issue there
is what qualifies as =22short=22. The definition I installed in 78e73e875=
was

+ /*
+ * We might eventually make max=5Fcover a user-settable parameter, but f= or
+ * now, just compute a reasonable value based on max=5Fwords and
+ * max=5Ffragments.
+ */
+ max=5Fcover =3D Max(max=5Fwords * 10, 100);
+ if (max=5Ffragments > 0)
+ max=5Fcover *=3D max=5Ffragments;

Looking at this again, I think the dependency on max=5Ffragments is just<= br /> wrong. That is what is causing your different results for different
= settings of Max=46ragments: larger values allow recognition of longer
candidate covers (=22cover=22 being jargon in this code for =22a substrin= g
satisfying the query=22). But there's no good reason for that. I'd misrea= d
the logic in mark=5Fhl=5Ffragments, which =22breaks the cover into smalle= r
fragments such that each fragment has at most max=5Fwords=22, to think th= at
it needed to see longer covers that it could divide into fragments.
= But actually max=5Ffragments limits the number of fragments it will retur= n
across all covers, and there doesn't seem to be a reason to connect that<= br /> parameter to the acceptable length of any particular cover. So dropping those two lines is enough to make the strange behavior across differing Max=46ragments go away.

The other issue is what to do after finding there's no match of max=5Fcov= er
or fewer tokens. As the code now stands, it'll just give up and return the initial bit of the text, likely with no query words. That's not
= great. I propose that we look for any match and return (highlight) just its first word.

SELECT id,
ts=5Fheadline('english', =22texts=22.=22fulltext=22, to=5Ftsquery('englis= h', 'amazon &
world'), 'StartSel=3D<<, StopSel=3D>>') AS =22preview=22
=46ROM texts;

id=3D1: Highlight word is the first one in = the result. Expectation: highlight
word is somewhere in the middle.

Meh --- I don't agree with that expectation. The fragment-based code does=
act that way, but the non-fragment path never has, so I think we'd make more people unhappy than happy if we change its behavior.

id=3D2: No highlight word at all.

Right, because there are no short matches to =22amazon & world=22 any= where.
With the attached proposed patch, we'll highlight whichever one of those<= br /> words appears first.

id=3D3: Highlight words are the first and l= ast one in the result. Not ideal
but ok-ish.

As I said, that's how non-fragment highlighting has always worked. It
will extend the quoted text, but not beyond min=5Fwords, which is a bit different from fragment highlighting.

SELECT id,
ts=5Fheadline('english', =22texts=22.=22fulltext=22, to=5Ftsquery('englis= h', 'amazon &
world'), 'Max=46ragments=3D3, StartSel=3D<<, StopSel=3D>>') A= S =22preview=22
=46ROM texts;

id=3D1: Wrong number of fragments (2) with = highlight words are returned.

I don't agree with this expectation either. There's only one reasonably sane match to 'amazon & world' in that text, and it's near the beginn= ing.
As the code stands, increasing max=5Ffragments eventually allows it to fi= nd
some less-sane matches, but that doesn't seem like an improvement.


In short, I suggest something about like the attached. =46or your id=3D2<= br /> example, which has only very far-apart occurrences of 'amazon' and
'world', this produces

<<world>> where fast runtimes make or break the popularity of= research
fields, this oversight has effectively

without fragmenting, and

researchers make the effort of understanding the inner workings of
these convenient black-boxes. In a <<world>> where fast runti= mes make
or break the popularity of research fields, this oversight has
effectively surrendered most

with fragmenting, which is okay by me given their historically different<= br /> behaviors. Otherwise, it gets rid of the strange changes in matching
behavior for different Max=46ragment values.

regards, tom lane

--637c6d72_3d1b58ba_89ae--