2011-02-15 00:34:20 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-03-31 01:49:06 +02:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-02-15 00:34:20 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2011-09-14 17:02:31 +02:00
|
|
|
/**
|
|
|
|
* @group search
|
|
|
|
*/
|
2011-08-08 00:14:23 +02:00
|
|
|
final class PhabricatorSearchEngineMySQL extends PhabricatorSearchEngine {
|
|
|
|
|
|
|
|
public function reindexAbstractDocument(
|
|
|
|
PhabricatorSearchAbstractDocument $doc) {
|
|
|
|
|
|
|
|
$phid = $doc->getPHID();
|
|
|
|
if (!$phid) {
|
|
|
|
throw new Exception("Document has no PHID!");
|
|
|
|
}
|
|
|
|
|
|
|
|
$store = new PhabricatorSearchDocument();
|
|
|
|
$store->setPHID($doc->getPHID());
|
|
|
|
$store->setDocumentType($doc->getDocumentType());
|
|
|
|
$store->setDocumentTitle($doc->getDocumentTitle());
|
|
|
|
$store->setDocumentCreated($doc->getDocumentCreated());
|
|
|
|
$store->setDocumentModified($doc->getDocumentModified());
|
|
|
|
$store->replace();
|
|
|
|
|
|
|
|
$conn_w = $store->establishConnection('w');
|
|
|
|
|
|
|
|
$field_dao = new PhabricatorSearchDocumentField();
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'DELETE FROM %T WHERE phid = %s',
|
|
|
|
$field_dao->getTableName(),
|
|
|
|
$phid);
|
|
|
|
foreach ($doc->getFieldData() as $field) {
|
|
|
|
list($ftype, $corpus, $aux_phid) = $field;
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'INSERT INTO %T (phid, phidType, field, auxPHID, corpus) '.
|
|
|
|
' VALUES (%s, %s, %s, %ns, %s)',
|
|
|
|
$field_dao->getTableName(),
|
|
|
|
$phid,
|
|
|
|
$doc->getDocumentType(),
|
|
|
|
$ftype,
|
|
|
|
$aux_phid,
|
|
|
|
$corpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$sql = array();
|
|
|
|
foreach ($doc->getRelationshipData() as $relationship) {
|
|
|
|
list($rtype, $to_phid, $to_type, $time) = $relationship;
|
|
|
|
$sql[] = qsprintf(
|
|
|
|
$conn_w,
|
|
|
|
'(%s, %s, %s, %s, %d)',
|
|
|
|
$phid,
|
|
|
|
$to_phid,
|
|
|
|
$rtype,
|
|
|
|
$to_type,
|
|
|
|
$time);
|
|
|
|
}
|
|
|
|
|
|
|
|
$rship_dao = new PhabricatorSearchDocumentRelationship();
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'DELETE FROM %T WHERE phid = %s',
|
|
|
|
$rship_dao->getTableName(),
|
|
|
|
$phid);
|
|
|
|
if ($sql) {
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'INSERT INTO %T'.
|
|
|
|
' (phid, relatedPHID, relation, relatedType, relatedTime) '.
|
|
|
|
' VALUES %Q',
|
|
|
|
$rship_dao->getTableName(),
|
|
|
|
implode(', ', $sql));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-02-15 00:34:20 +01:00
|
|
|
|
2011-06-15 16:43:43 +02:00
|
|
|
/**
|
|
|
|
* Rebuild the PhabricatorSearchAbstractDocument that was used to index
|
|
|
|
* an object out of the index itself. This is primarily useful for debugging,
|
|
|
|
* as it allows you to inspect the search index representation of a
|
|
|
|
* document.
|
|
|
|
*
|
|
|
|
* @param phid PHID of a document which exists in the search index.
|
|
|
|
* @return null|PhabricatorSearchAbstractDocument Abstract document object
|
|
|
|
* which corresponds to the original abstract document used to
|
|
|
|
* build the document index.
|
|
|
|
*/
|
|
|
|
public function reconstructDocument($phid) {
|
|
|
|
$dao_doc = new PhabricatorSearchDocument();
|
|
|
|
$dao_field = new PhabricatorSearchDocumentField();
|
|
|
|
$dao_relationship = new PhabricatorSearchDocumentRelationship();
|
|
|
|
|
|
|
|
$t_doc = $dao_doc->getTableName();
|
|
|
|
$t_field = $dao_field->getTableName();
|
|
|
|
$t_relationship = $dao_relationship->getTableName();
|
|
|
|
|
|
|
|
$doc = queryfx_one(
|
|
|
|
$dao_doc->establishConnection('r'),
|
|
|
|
'SELECT * FROM %T WHERE phid = %s',
|
|
|
|
$t_doc,
|
|
|
|
$phid);
|
|
|
|
|
|
|
|
if (!$doc) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$fields = queryfx_all(
|
|
|
|
$dao_field->establishConnection('r'),
|
|
|
|
'SELECT * FROM %T WHERE phid = %s',
|
|
|
|
$t_field,
|
|
|
|
$phid);
|
|
|
|
|
|
|
|
$relationships = queryfx_all(
|
|
|
|
$dao_relationship->establishConnection('r'),
|
|
|
|
'SELECT * FROM %T WHERE phid = %s',
|
|
|
|
$t_relationship,
|
|
|
|
$phid);
|
|
|
|
|
|
|
|
$adoc = id(new PhabricatorSearchAbstractDocument())
|
|
|
|
->setPHID($phid)
|
|
|
|
->setDocumentType($doc['documentType'])
|
|
|
|
->setDocumentTitle($doc['documentTitle'])
|
|
|
|
->setDocumentCreated($doc['documentCreated'])
|
|
|
|
->setDocumentModified($doc['documentModified']);
|
|
|
|
|
|
|
|
foreach ($fields as $field) {
|
|
|
|
$adoc->addField(
|
|
|
|
$field['field'],
|
|
|
|
$field['corpus'],
|
|
|
|
$field['auxPHID']);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($relationships as $relationship) {
|
|
|
|
$adoc->addRelationship(
|
|
|
|
$relationship['relation'],
|
|
|
|
$relationship['relatedPHID'],
|
|
|
|
$relationship['relatedType'],
|
|
|
|
$relationship['relatedTime']);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $adoc;
|
|
|
|
}
|
|
|
|
|
2011-02-15 00:34:20 +01:00
|
|
|
public function executeSearch(PhabricatorSearchQuery $query) {
|
|
|
|
|
|
|
|
$where = array();
|
|
|
|
$join = array();
|
|
|
|
$order = 'ORDER BY documentCreated DESC';
|
|
|
|
|
|
|
|
$dao_doc = new PhabricatorSearchDocument();
|
|
|
|
$dao_field = new PhabricatorSearchDocumentField();
|
|
|
|
|
|
|
|
$t_doc = $dao_doc->getTableName();
|
|
|
|
$t_field = $dao_field->getTableName();
|
|
|
|
|
|
|
|
$conn_r = $dao_doc->establishConnection('r');
|
|
|
|
|
|
|
|
$q = $query->getQuery();
|
|
|
|
|
|
|
|
if (strlen($q)) {
|
|
|
|
$join[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
"{$t_field} field ON field.phid = document.phid");
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
2012-03-31 01:49:06 +02:00
|
|
|
'MATCH(corpus) AGAINST (%s IN BOOLEAN MODE)',
|
2011-02-15 00:34:20 +01:00
|
|
|
$q);
|
2011-03-23 01:19:52 +01:00
|
|
|
|
Improve search result listing
Summary:
Make it prettier, paginate, add user pictures, show document types, clean some
stuff up a little. Plenty of room for improvement but this should make it a lot
more useful.
Test Plan:
Here's what the new one looks like:
https://secure.phabricator.com/file/view/PHID-FILE-edce2b83c2e3a121c2b7/
Reviewed By: jungejason
Reviewers: tomo, jungejason, aran, tuomaspelkonen, mroch
Commenters: tomo
CC: aran, tomo, jungejason, epriestley
Differential Revision: 545
2011-06-28 23:35:02 +02:00
|
|
|
// When searching for a string, promote user listings above other
|
|
|
|
// listings.
|
|
|
|
$order = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'ORDER BY
|
|
|
|
IF(documentType = %s, 0, 1) ASC,
|
|
|
|
MAX(MATCH(corpus) AGAINST (%s)) DESC',
|
|
|
|
'USER',
|
|
|
|
$q);
|
2011-03-23 01:19:52 +01:00
|
|
|
|
2011-02-15 00:34:20 +01:00
|
|
|
$field = $query->getParameter('field');
|
|
|
|
if ($field/* && $field != AdjutantQuery::FIELD_ALL*/) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'field.field = %s',
|
|
|
|
$field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-04 03:34:55 +02:00
|
|
|
$exclude = $query->getParameter('exclude');
|
|
|
|
if ($exclude) {
|
|
|
|
$where[] = qsprintf($conn_r, 'document.phid != %s', $exclude);
|
|
|
|
}
|
|
|
|
|
2011-02-15 00:34:20 +01:00
|
|
|
if ($query->getParameter('type')) {
|
2011-02-19 02:16:00 +01:00
|
|
|
if (strlen($q)) {
|
|
|
|
// TODO: verify that this column actually does something useful in query
|
|
|
|
// plans once we have nontrivial amounts of data.
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'field.phidType = %s',
|
|
|
|
$query->getParameter('type'));
|
|
|
|
}
|
2011-02-15 00:34:20 +01:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'document.documentType = %s',
|
|
|
|
$query->getParameter('type'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'author',
|
2011-02-19 02:16:00 +01:00
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR);
|
|
|
|
|
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'open',
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_OPEN);
|
|
|
|
|
2011-02-19 02:36:25 +01:00
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'owner',
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_OWNER);
|
|
|
|
|
2011-02-21 05:37:50 +01:00
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'project',
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_PROJECT);
|
|
|
|
|
2011-06-20 06:02:48 +02:00
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'repository',
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY);
|
|
|
|
|
2011-02-19 02:16:00 +01:00
|
|
|
/*
|
2011-02-15 00:34:20 +01:00
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'reviewer',
|
|
|
|
AdjutantRelationship::RELATIONSHIP_REVIEWER);
|
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'subscriber',
|
|
|
|
AdjutantRelationship::RELATIONSHIP_SUBSCRIBER);
|
|
|
|
$join[] = $this->joinRelationship(
|
|
|
|
$conn_r,
|
|
|
|
$query,
|
|
|
|
'repository',
|
|
|
|
AdjutantRelationship::RELATIONSHIP_REPOSITORY);
|
|
|
|
*/
|
|
|
|
$join = array_filter($join);
|
|
|
|
|
|
|
|
foreach ($join as $key => $clause) {
|
|
|
|
$join[$key] = ' JOIN '.$clause;
|
|
|
|
}
|
|
|
|
$join = implode(' ', $join);
|
|
|
|
|
|
|
|
if ($where) {
|
|
|
|
$where = 'WHERE '.implode(' AND ', $where);
|
|
|
|
} else {
|
|
|
|
$where = '';
|
|
|
|
}
|
|
|
|
|
Improve search result listing
Summary:
Make it prettier, paginate, add user pictures, show document types, clean some
stuff up a little. Plenty of room for improvement but this should make it a lot
more useful.
Test Plan:
Here's what the new one looks like:
https://secure.phabricator.com/file/view/PHID-FILE-edce2b83c2e3a121c2b7/
Reviewed By: jungejason
Reviewers: tomo, jungejason, aran, tuomaspelkonen, mroch
Commenters: tomo
CC: aran, tomo, jungejason, epriestley
Differential Revision: 545
2011-06-28 23:35:02 +02:00
|
|
|
$offset = (int)$query->getParameter('offset', 0);
|
|
|
|
$limit = (int)$query->getParameter('limit', 25);
|
|
|
|
|
2011-02-15 00:34:20 +01:00
|
|
|
$hits = queryfx_all(
|
|
|
|
$conn_r,
|
2011-03-23 01:19:52 +01:00
|
|
|
'SELECT
|
2012-04-21 00:42:36 +02:00
|
|
|
document.phid
|
2011-03-23 01:19:52 +01:00
|
|
|
FROM %T document
|
|
|
|
%Q
|
|
|
|
%Q
|
|
|
|
GROUP BY document.phid
|
|
|
|
%Q
|
Improve search result listing
Summary:
Make it prettier, paginate, add user pictures, show document types, clean some
stuff up a little. Plenty of room for improvement but this should make it a lot
more useful.
Test Plan:
Here's what the new one looks like:
https://secure.phabricator.com/file/view/PHID-FILE-edce2b83c2e3a121c2b7/
Reviewed By: jungejason
Reviewers: tomo, jungejason, aran, tuomaspelkonen, mroch
Commenters: tomo
CC: aran, tomo, jungejason, epriestley
Differential Revision: 545
2011-06-28 23:35:02 +02:00
|
|
|
LIMIT %d, %d',
|
2011-02-15 00:34:20 +01:00
|
|
|
$t_doc,
|
|
|
|
$join,
|
|
|
|
$where,
|
Improve search result listing
Summary:
Make it prettier, paginate, add user pictures, show document types, clean some
stuff up a little. Plenty of room for improvement but this should make it a lot
more useful.
Test Plan:
Here's what the new one looks like:
https://secure.phabricator.com/file/view/PHID-FILE-edce2b83c2e3a121c2b7/
Reviewed By: jungejason
Reviewers: tomo, jungejason, aran, tuomaspelkonen, mroch
Commenters: tomo
CC: aran, tomo, jungejason, epriestley
Differential Revision: 545
2011-06-28 23:35:02 +02:00
|
|
|
$order,
|
|
|
|
$offset,
|
|
|
|
$limit);
|
2011-02-15 00:34:20 +01:00
|
|
|
|
[NO CLUE WHAT I'M DOING] Add an Elasticsearch engine
Summary:
I have no idea what I'm doing, but here's part of an elasticsearch engine. These things work:
- Indexing stuff (??)
- Searching for text/type?
- Reconstructing things??
All the complicated stuff doesn't work. I'm having a hard time figuring out the best way to model things because elasticsearch's documentation is not exactly the most complete or illuminating.
@amckinley, does this look sane-ish so far? Particularly, the /phabricator/<type>/<phid>/ URI scheme and how I've set up the relationships and fields in the documents?
How should I model the relationship and field queries? I want, like, an "equal" query but it seems like I've got "text" or "term" to work with and neither are exact match? And "term" doesn't consider PHIDs to be terms since they have hyphens in them?
I'll keep kind of slogging my way forward here but if you have valuable wisdom to share it would probably get me to a better end state much faster. The whole query construction phase is pretty much black magic to me.
Test Plan: nyancat
Reviewers: amckinley, vrana
Reviewed By: vrana
CC: jungejason, tuomaspelkonen, aran, 20after4, vrana
Differential Revision: https://secure.phabricator.com/D790
2012-04-21 00:33:09 +02:00
|
|
|
return ipull($hits, 'phid');
|
2011-02-15 00:34:20 +01:00
|
|
|
}
|
|
|
|
|
Improve elasticsearch
Summary: I thought that this will be fun but the elasticsearch API is horrible and the documentation is poor.
Test Plan:
Search for:
- string
- author
- author, owner
- string, author
- open
- string, open, author
- string, exclude
- several authors, several owners
- nothing
- probably all other combinations
Normally, such an exhaustive test plan wouldn't be required but each combination requires a completely different query.
Reviewers: epriestley, jungejason
Reviewed By: epriestley
CC: aran, Koolvin, btrahan
Differential Revision: https://secure.phabricator.com/D2298
2012-04-21 02:09:30 +02:00
|
|
|
protected function joinRelationship(
|
|
|
|
AphrontDatabaseConnection $conn,
|
|
|
|
PhabricatorSearchQuery $query,
|
|
|
|
$field,
|
|
|
|
$type) {
|
|
|
|
|
2011-02-19 02:16:00 +01:00
|
|
|
$phids = $query->getParameter($field, array());
|
|
|
|
if (!$phids) {
|
2011-02-15 00:34:20 +01:00
|
|
|
return null;
|
|
|
|
}
|
2011-02-19 02:16:00 +01:00
|
|
|
|
|
|
|
$is_existence = false;
|
|
|
|
switch ($type) {
|
|
|
|
case PhabricatorSearchRelationship::RELATIONSHIP_OPEN:
|
|
|
|
$is_existence = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$sql = qsprintf(
|
2011-02-15 00:34:20 +01:00
|
|
|
$conn,
|
2011-02-19 02:16:00 +01:00
|
|
|
'%T AS %C ON %C.phid = document.phid AND %C.relation = %s',
|
|
|
|
id(new PhabricatorSearchDocumentRelationship())->getTableName(),
|
2011-02-15 00:34:20 +01:00
|
|
|
$field,
|
|
|
|
$field,
|
|
|
|
$field,
|
2011-02-19 02:16:00 +01:00
|
|
|
$type);
|
|
|
|
|
|
|
|
if (!$is_existence) {
|
|
|
|
$sql .= qsprintf(
|
|
|
|
$conn,
|
|
|
|
' AND %C.relatedPHID in (%Ls)',
|
|
|
|
$field,
|
|
|
|
$phids);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $sql;
|
2011-02-15 00:34:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|