[TikiWiki-commits] [Git][tikiwiki/tiki][27.x] [FIX] Search: fix morelikethis for MySQL and manticore
"Victor Emanouilov \(@kroky\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <69689efa70c9b_2c181b1812325@gitlab-sidekiq-low-urgency-cpu-bound-v2-66fcfd8d9-45sl6.mail> |
Victor Emanouilov pushed to branch 27.x at Tiki Wiki CMS Groupware / Tiki
Commits:
81f9751f by Josaphat Imani at 2026-01-15T10:00:02+02:00
[FIX] Search: fix morelikethis for MySQL and manticore
---
* Autoload classes
* Added MoreLikeThis tests for MySQL and Manticore
* [FIX] Search: fix morelikethis for mySQL and manticore
See merge request tikiwiki/tiki!6767
- - - - -
8 changed files:
- lib/core/Search/Manticore/Index.php
- lib/core/Search/Manticore/PdoClient.php
- lib/core/Search/Manticore/QueryBuilder.php
- lib/core/Search/MySql/QueryBuilder.php
- + lib/test/core/Search/AbstractMoreLikeThis.php
- lib/test/core/Search/Elastic/MoreLikeThisTest.php
- + lib/test/core/Search/Manticore/MoreLikeThisTest.php
- + lib/test/core/Search/MySql/MoreLikeThisTest.php
Changes:
=====================================
lib/core/Search/Manticore/Index.php
=====================================
@@ -421,6 +421,11 @@ class Index implements \Search_Index_Interface, \Search_Index_QueryRepository
return $search;
}
+ public function getIndexTableName()
+ {
+ return $this->index;
+ }
+
public function find(\Search_Query_Interface $query, $resultStart, $resultCount)
{
$builder = new QueryBuilder($this);
=====================================
lib/core/Search/Manticore/PdoClient.php
=====================================
@@ -352,7 +352,7 @@ class PdoClient
public function document($index, $type, $id): ResultSet
{
$stmt = $this->prepareAndExecute("SELECT * FROM $index WHERE object_type = :object_type AND object_id = :object_id", ['object_type' => $type, 'object_id' => $id]);
- return new ResultSet($stmt->fetch());
+ return new ResultSet($stmt->fetch(), 1, 0, 1);
}
public function optimize($index)
=====================================
lib/core/Search/Manticore/QueryBuilder.php
=====================================
@@ -104,6 +104,12 @@ class QueryBuilder
try {
if (! $node instanceof NotX && count($fields) == 1 && $this->isFullText($node)) {
$query = $this->fieldBuilder->build($node, $this->factory);
+ if ($node instanceof MoreLikeThis) {
+ $type = $node->getObjectType();
+ $object = $node->getObjectId();
+ $query = $this->getDocumentContent($type, $object);
+ }
+
if (preg_match('/^[\d\.]+$/', $query)) {
// version strings should be phrases
$query = '"' . $query . '"';
@@ -194,6 +200,13 @@ class QueryBuilder
$this->select[$key] = $query;
return "$key = 0";
}
+ $query = preg_replace_callback(
+ '/\s(AND|OR)\s/',
+ function ($matches) {
+ return $matches[1] === 'AND' ? ' OR ' : ' AND ';
+ },
+ $query
+ );
$query = str_replace(' = ', ' <> ', $query);
$query = str_replace(' < ', ' >= ', $query);
$query = str_replace(' > ', ' <= ', $query);
@@ -390,4 +403,14 @@ class QueryBuilder
// single quotes require only one slash escape
return addcslashes($qs, "'");
}
+
+ private function getDocumentContent($type, $object)
+ {
+ $doc = $this->pdo_client->document($this->index->getIndexTableName(), $type, $object, 'contents');
+ if (! empty($doc['contents'])) {
+ return $doc['contents'];
+ }
+
+ return '';
+ }
}
=====================================
lib/core/Search/MySql/QueryBuilder.php
=====================================
@@ -72,7 +72,13 @@ class Search_MySql_QueryBuilder
// $query contains the token string to compare against $fields[0] in the unified search table
// $fields[0] can be i.e 'allowed_users', 'allowed_groups'
$query = $this->fieldBuilder->build($node, $this->factory);
- $str = $this->db->qstr($query);
+ if ($node instanceof MoreLikeThis) {
+ $type = $node->getObjectType();
+ $object = $node->getObjectId();
+ $str = $node->getContent() ?: $this->getDocumentContent($type, $object);
+ } else {
+ $str = $this->db->qstr($query);
+ }
$this->requireIndex($fields[0], 'fulltext', $node->getWeight());
$type = $this->fieldBuilder->isInverted()
? 'NOT MATCH'
@@ -173,4 +179,15 @@ class Search_MySql_QueryBuilder
{
return $node->getValue($this->factory)->getValue();
}
+
+ private function getDocumentContent($type, $object)
+ {
+ $results = $this->table->fetchAllIndex(['contents'], ['object_type' => $type, 'object_id' => $object]);
+
+ if (! empty($results[0]['contents'])) {
+ return $this->db->qstr($results[0]['contents']);
+ }
+
+ return '';
+ }
}
=====================================
lib/test/core/Search/AbstractMoreLikeThis.php
=====================================
@@ -0,0 +1,93 @@
+<?php
+
+namespace Search;
+
+use PHPUnit\Framework\TestCase;
+use Search_ContentSource_Static;
+use Search_Indexer;
+use Search_Query;
+
+abstract class AbstractMoreLikeThis extends TestCase
+{
+ protected $index;
+
+ abstract protected function getIndex();
+
+ protected function setUp(): void
+ {
+ $this->index = $this->getIndex();
+ $this->index->destroy();
+
+ $this->populate($this->index);
+ }
+
+ protected function tearDown(): void
+ {
+ if ($this->index) {
+ $this->index->destroy();
+ }
+ }
+
+ public function populate($index)
+ {
+ $data = [
+ 'X' => [
+ 'wiki_content' => 'this does not work',
+ ],
+ ];
+
+ $words = ['hello', 'world', 'some', 'random', 'content', 'populated', 'through', 'automatic', 'sampling'];
+
+ // Generate 50 documents with random words (in a stable way)
+ foreach (range(1, 50) as $doc) {
+ $parts = [];
+ foreach ($words as $key => $word) {
+ if ($doc % ($key + 2) === 0) {
+ $parts[] = $word;
+ $parts[] = $word;
+ $parts[] = $word;
+ }
+ }
+
+ $data[$doc] = [
+ 'object_type' => 'wiki page',
+ 'object_id' => $doc,
+ 'wiki_content' => implode(' ', $parts),
+ ];
+ }
+
+ $source = new Search_ContentSource_Static(
+ $data,
+ [
+ 'object_type' => 'identifier',
+ 'object_id' => 'identifier',
+ 'wiki_content' => 'plaintext',
+ ]
+ );
+
+ $indexer = new Search_Indexer($index);
+ $indexer->addContentSource('wiki page', $source);
+
+ $indexer->rebuild();
+ }
+
+ public function testObtainSimilarDocument()
+ {
+ $query = new Search_Query();
+ $query->filterSimilar('wiki page', 12);
+
+ $results = $query->search($this->index);
+
+ $this->assertGreaterThan(0, count($results));
+ }
+
+ public function testDocumentTooDifferent()
+ {
+ $query = new Search_Query();
+ $query->filterSimilar('wiki page', 'X');
+
+ $results = $query->search($this->index);
+
+ $this->assertCount(0, $results);
+ }
+}
=====================================
lib/test/core/Search/Elastic/MoreLikeThisTest.php
=====================================
@@ -1,10 +1,13 @@
<?php
-class Search_Elastic_MoreLikeThisTest extends PHPUnit\Framework\TestCase
-{
- private $index;
+namespace Search\Elastic;
+
+use Search_Elastic_Connection;
+use Search_Elastic_Index;
- protected function setUp(): void
+class Search_Elastic_MoreLikeThisTest extends \Search\AbstractMoreLikeThis
+{
+ protected function getIndex()
{
$elasticSearchHost = empty(getenv('ELASTICSEARCH_HOST')) ? 'localhost' : getenv('ELASTICSEARCH_HOST');
$connection = Search_Elastic_Connection::build('http://' . $elasticSearchHost . ':9200');
@@ -15,79 +18,6 @@ class Search_Elastic_MoreLikeThisTest extends PHPUnit\Framework\TestCase
$this->markTestSkipped('Elasticsearch needs to be available on ' . $elasticSearchHost . ':9200 for the test to run.');
}
- $this->index = new Search_Elastic_Index($connection, 'test_index');
- $this->index->destroy();
-
- $this->populate($this->index);
- }
-
- protected function tearDown(): void
- {
- if ($this->index) {
- $this->index->destroy();
- }
- }
-
- public function populate($index)
- {
- $data = [
- 'X' => [
- 'wiki_content' => 'this does not work',
- ],
- ];
-
- $words = ['hello', 'world', 'some', 'random', 'content', 'populated', 'through', 'automatic', 'sampling'];
-
- // Generate 50 documents with random words (in a stable way)
- foreach (range(1, 50) as $doc) {
- $parts = [];
- foreach ($words as $key => $word) {
- if ($doc % ($key + 2) === 0) {
- $parts[] = $word;
- $parts[] = $word;
- $parts[] = $word;
- }
- }
-
- $data[$doc] = [
- 'object_type' => 'wiki page',
- 'object_id' => $doc,
- 'wiki_content' => implode(' ', $parts),
- ];
- }
-
- $source = new Search_ContentSource_Static(
- $data,
- [
- 'object_type' => 'identifier',
- 'object_id' => 'identifier',
- 'wiki_content' => 'plaintext',
- ]
- );
-
- $indexer = new Search_Indexer($index);
- $indexer->addContentSource('wiki page', $source);
-
- $indexer->rebuild();
- }
-
- public function testObtainSimilarDocument()
- {
- $query = new Search_Query();
- $query->filterSimilar('wiki page', 12);
-
- $results = $query->search($this->index);
-
- $this->assertGreaterThan(0, count($results));
- }
-
- public function testDocumentTooDifferent()
- {
- $query = new Search_Query();
- $query->filterSimilar('wiki page', 'X');
-
- $results = $query->search($this->index);
-
- $this->assertCount(0, $results);
+ return new Search_Elastic_Index($connection, 'test_index');
}
}
=====================================
lib/test/core/Search/Manticore/MoreLikeThisTest.php
=====================================
@@ -0,0 +1,8 @@
+<?php
+
+namespace Search\Manticore;
+
+class MoreLikeThisTest extends \Search\AbstractMoreLikeThis
+{
+ use IndexBuilder;
+}
=====================================
lib/test/core/Search/MySql/MoreLikeThisTest.php
=====================================
@@ -0,0 +1,14 @@
+<?php
+
+namespace Search\MySql;
+
+use Search_MySql_Index;
+use TikiDb;
+
+class MoreLikeThisTest extends \Search\AbstractMoreLikeThis
+{
+ protected function getIndex()
+ {
+ return new Search_MySql_Index(TikiDb::get(), 'test_index');
+ }
+}
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/81f9751f6e304c57ca5317078df5c5fde7666307
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/81f9751f6e304c57ca5317078df5c5fde7666307
You're receiving this email because of your account on gitlab.com.
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs