Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Content\Search\Elastic;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -174,8 +174,8 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
}
|
||||
|
||||
/* Minimum views / comments / reviews */
|
||||
foreach ( array( 'minimumViews' => 'index_views', 'minimumComments' => 'index_comments', 'minimumReviews' => 'index_reviews' ) as $filterKey => $indexKey )
|
||||
/* Minimum comments / reviews */
|
||||
foreach ( array( 'minimumComments' => 'index_comments', 'minimumReviews' => 'index_reviews' ) as $filterKey => $indexKey )
|
||||
{
|
||||
if ( $filter->$filterKey )
|
||||
{
|
||||
@@ -204,11 +204,14 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
|
||||
/* Put it together */
|
||||
$contentFilterConditions[] = Index::convertConditionsToQuery( $conditions );
|
||||
if( \count( $conditions ) )
|
||||
{
|
||||
$contentFilterConditions[] = Index::convertConditionsToQuery( $conditions );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Put them together */
|
||||
if ( count( $contentFilterConditions ) > 1 )
|
||||
if ( \count( $contentFilterConditions ) > 1 )
|
||||
{
|
||||
$this->filters[] = array(
|
||||
'bool' => array(
|
||||
@@ -218,11 +221,17 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
elseif ( $type )
|
||||
{
|
||||
$this->filters[] = $contentFilterConditions[0];
|
||||
if( \count( $contentFilterConditions ) )
|
||||
{
|
||||
$this->filters[] = $contentFilterConditions[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->mustNot[] = $contentFilterConditions[0];
|
||||
if( \count( $contentFilterConditions ) )
|
||||
{
|
||||
$this->mustNot[] = $contentFilterConditions[0];
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -236,7 +245,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
*/
|
||||
public function filterByAuthor( $author )
|
||||
{
|
||||
if ( is_array( $author ) )
|
||||
if ( \is_array( $author ) )
|
||||
{
|
||||
$this->filters[] = array( 'terms' => array( 'index_author' => $author ) );
|
||||
}
|
||||
@@ -262,7 +271,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
'exists' => array( 'field' => 'index_club_id' )
|
||||
);
|
||||
}
|
||||
elseif ( is_array( $club ) )
|
||||
elseif ( \is_array( $club ) )
|
||||
{
|
||||
$this->filters[] = array(
|
||||
'terms' => array( 'index_club_id' => $club )
|
||||
@@ -274,6 +283,25 @@ class _Query extends \IPS\Content\Search\Query
|
||||
'term' => array( 'index_club_id' => $club instanceof \IPS\Member\Club ? $club->id : $club )
|
||||
);
|
||||
}
|
||||
|
||||
/* Get the list of valid classes */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter', FALSE ) as $object )
|
||||
{
|
||||
foreach ( $object->classes as $class )
|
||||
{
|
||||
if ( \in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
$classesChecked[] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Give content item classes a chance to inspect and manipulate filters */
|
||||
$filters = array();
|
||||
foreach( $classesChecked as $itemClass )
|
||||
{
|
||||
$itemClass::searchEngineFiltering( $filters, $this );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -318,7 +346,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
foreach ( $object->classes as $class )
|
||||
{
|
||||
if ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
if ( \in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
$classesChecked[] = $class;
|
||||
}
|
||||
@@ -399,7 +427,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
*
|
||||
* @param bool $includeContainers Include content in containers the user follows?
|
||||
* @param bool $includeItems Include items and comments/reviews on items the user follows?
|
||||
* @param bool $includeContainers Include content posted by members the user follows?
|
||||
* @param bool $includeMembers Include content posted by members the user follows?
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
*/
|
||||
public function filterByFollowed( $includeContainers, $includeItems, $includeMembers )
|
||||
@@ -477,7 +505,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
$followedItems[ $follow['follow_area'] ][] = $follow['follow_rel_id'];
|
||||
}
|
||||
else if( in_array( $follow['follow_area'], $containerCase ) )
|
||||
else if( \in_array( $follow['follow_area'], $containerCase ) )
|
||||
{
|
||||
$followedContainers[ $follow['follow_area'] ][] = $follow['follow_rel_id'];
|
||||
}
|
||||
@@ -537,7 +565,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
|
||||
/* Put it all together */
|
||||
if ( count( $conditions ) )
|
||||
if ( \count( $conditions ) )
|
||||
{
|
||||
$this->filters[] = array( 'bool' => array( 'should' => $conditions ) );
|
||||
}
|
||||
@@ -646,7 +674,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
|
||||
/* And get the times each individual item was read for later */
|
||||
$items = $this->member->markersItems( $application, \IPS\Content\Item::makeMarkerKey( $containerId ) );
|
||||
if ( count( $items ) )
|
||||
if ( \count( $items ) )
|
||||
{
|
||||
foreach( $items as $mid => $mtime )
|
||||
{
|
||||
@@ -656,10 +684,10 @@ class _Query extends \IPS\Content\Search\Query
|
||||
in it's old location, with the previously 'read' time. In this circumstance, we need
|
||||
to only use more recent read time, otherwise the topic may be incorrectly included
|
||||
in the results */
|
||||
if ( in_array( $mid, $markers ) )
|
||||
if ( \in_array( $mid, $markers ) )
|
||||
{
|
||||
$_key = array_search( $mid, $markers );
|
||||
$_mtime = intval( mb_substr( $_key, 0, mb_strpos( $_key, '.' ) ) );
|
||||
$_mtime = \intval( mb_substr( $_key, 0, mb_strpos( $_key, '.' ) ) );
|
||||
if ( $_mtime < $mtime )
|
||||
{
|
||||
unset( $markers[ $_key ] );
|
||||
@@ -704,7 +732,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
|
||||
$notIn = array();
|
||||
if ( count( $markers ) )
|
||||
if ( \count( $markers ) )
|
||||
{
|
||||
$useIds = array_flip( $markers );
|
||||
|
||||
@@ -713,7 +741,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
if ( isset( $class::$databaseColumnMap[ $k ] ) )
|
||||
{
|
||||
if ( is_array( $class::$databaseColumnMap[ $k ] ) )
|
||||
if ( \is_array( $class::$databaseColumnMap[ $k ] ) )
|
||||
{
|
||||
foreach ( $class::$databaseColumnMap[ $k ] as $v )
|
||||
{
|
||||
@@ -726,7 +754,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
}
|
||||
}
|
||||
$dateColumnExpression = count( $dateColumns ) > 1 ? ( 'GREATEST(' . implode( ',', $dateColumns ) . ')' ) : array_pop( $dateColumns );
|
||||
$dateColumnExpression = \count( $dateColumns ) > 1 ? ( 'GREATEST(' . implode( ',', $dateColumns ) . ')' ) : array_pop( $dateColumns );
|
||||
|
||||
foreach( \IPS\Db::i()->select( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnId. ' as _id, ' . $dateColumnExpression . ' as _date', $class::$databaseTable, \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnId, array_keys( $useIds ) ) ) as $row )
|
||||
{
|
||||
@@ -735,7 +763,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
if ( $useIds[ $row['_id'] ] >= $row['_date'] )
|
||||
{
|
||||
/* Still read */
|
||||
$notIn[] = intval( $row['_id'] );
|
||||
$notIn[] = \intval( $row['_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -747,7 +775,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
'filter' => $classConditions
|
||||
)
|
||||
);
|
||||
if ( count( $notIn ) )
|
||||
if ( \count( $notIn ) )
|
||||
{
|
||||
$_condition['bool']['must_not'] = array(
|
||||
'terms' => array(
|
||||
@@ -760,7 +788,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
}
|
||||
|
||||
/* Put it all together */
|
||||
if ( count( $conditions ) )
|
||||
if ( \count( $conditions ) )
|
||||
{
|
||||
$this->filters[] = array(
|
||||
'bool' => array(
|
||||
@@ -907,7 +935,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
public function search( $term = NULL, $tags = NULL, $method = 1, $operator = NULL )
|
||||
{
|
||||
/* If we're looking for more results than we can fetch, we don't need to ask Elastic Search */
|
||||
if( ( $this->offset + $this->resultsToGet ) >= \IPS\Settings::i()->search_index_maxresults )
|
||||
if( ( $this->offset + $this->resultsToGet ) > \IPS\Settings::i()->search_index_maxresults )
|
||||
{
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
@@ -920,11 +948,12 @@ class _Query extends \IPS\Content\Search\Query
|
||||
if ( $term !== NULL or $tags !== NULL )
|
||||
{
|
||||
$searchConditions = array();
|
||||
$titleField = \IPS\Settings::i()->search_title_boost ? ( 'index_title^' . intval( \IPS\Settings::i()->search_title_boost ) ) : 'index_title';
|
||||
$titleField = \IPS\Settings::i()->search_title_boost ? ( 'index_title^' . \intval( \IPS\Settings::i()->search_title_boost ) ) : 'index_title';
|
||||
|
||||
/* Build the condition for the search term */
|
||||
if ( $term !== NULL )
|
||||
{
|
||||
/* If term is in "quotes" handle it as a phrase */
|
||||
if ( static::termIsPhrase( $term ) )
|
||||
{
|
||||
$term = trim( $term, '"' );
|
||||
@@ -937,6 +966,30 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$searchConditions[] = array( 'multi_match' => array( 'query' => $term, 'fields' => array( 'index_content', $titleField ), 'type' => 'phrase' ) );
|
||||
}
|
||||
}
|
||||
/* If term contains * wildcard, but doesn't start with it (from elasticsearch docs: "In order to prevent extremely slow wildcard queries, a wildcard term should not start with one of the wildcards * or ?"), handle it as a wildcard search - NOTE this will not use the analyzer */
|
||||
elseif ( preg_match( '/^[^\s\*].*\*.*$/', $term ) )
|
||||
{
|
||||
if ( $method & static::TERM_TITLES_ONLY )
|
||||
{
|
||||
$searchConditions[] = array( 'wildcard' => array( 'index_title' => array( 'value' => $term ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$searchConditions[] = array(
|
||||
'bool' => array(
|
||||
'should' => array(
|
||||
array(
|
||||
'wildcard' => array( 'index_title' => ( \IPS\Settings::i()->search_title_boost ? array( 'value' => $term, 'boost' => \intval( \IPS\Settings::i()->search_title_boost ) ) : array( 'value' => $term ) ) )
|
||||
),
|
||||
array(
|
||||
'wildcard' => array( 'index_content' => array( 'value' => $term ) )
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Otherwise just do it as a match search */
|
||||
else
|
||||
{
|
||||
if ( $method & static::TERM_TITLES_ONLY )
|
||||
@@ -988,7 +1041,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$filters[] = array( 'terms' => array( 'index_permissions' => array_merge( $this->permissionArray(), array( '*' ) ) ) );
|
||||
if ( $this->hiddenStatuses !== NULL )
|
||||
{
|
||||
if ( is_array( $this->hiddenStatuses ) )
|
||||
if ( \is_array( $this->hiddenStatuses ) )
|
||||
{
|
||||
$filters[] = array( 'terms' => array( 'index_hidden' => $this->hiddenStatuses ) );
|
||||
}
|
||||
@@ -1018,8 +1071,9 @@ class _Query extends \IPS\Content\Search\Query
|
||||
'query' => $query,
|
||||
'linear' => array(
|
||||
'index_date_updated' => array(
|
||||
'scale' => intval( \IPS\Settings::i()->search_decay_days ) . 'd',
|
||||
'decay' => number_format( \IPS\Settings::i()->search_decay_factor, 1, '.', '' )
|
||||
'scale' => \intval( \IPS\Settings::i()->search_decay_days ) . 'd',
|
||||
'decay' => number_format( \IPS\Settings::i()->search_decay_factor, 1, '.', '' ),
|
||||
'origin' => time(),
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1034,8 +1088,12 @@ class _Query extends \IPS\Content\Search\Query
|
||||
'query' => $query,
|
||||
'script_score' => array(
|
||||
'script' => array(
|
||||
'inline' => "doc['index_author'].value == " . intval( $this->member->member_id ) . " ? ( _score * " . number_format( \IPS\Settings::i()->search_elastic_self_boost, 1, '.', '' ) . " ) : _score",
|
||||
'lang' => 'painless'
|
||||
'source' => "doc['index_author'].value == params.param_memberId ? ( _score * Float.parseFloat( params.param_booster ) ) : _score",
|
||||
'lang' => 'painless',
|
||||
'params' => array(
|
||||
'param_memberId' => \intval( $this->member->member_id ),
|
||||
'param_booster' => number_format( \IPS\Settings::i()->search_elastic_self_boost, 1, '.', '' )
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1057,7 +1115,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
|
||||
|
||||
/* Make the call! */
|
||||
$return = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( $json )->decodeJson();
|
||||
if ( isset( $return['error'] ) )
|
||||
@@ -1065,14 +1123,15 @@ class _Query extends \IPS\Content\Search\Query
|
||||
\IPS\Log::log( print_r( $return['error'], TRUE ), 'elasticsearch' );
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
|
||||
/* Set results */
|
||||
|
||||
/* Set results */
|
||||
$total = $return['hits']['total']['value'] ?? $return['hits']['total'];
|
||||
return new \IPS\Content\Search\Results( array_map( function( $hit ) {
|
||||
$indexData = $hit['_source'];
|
||||
$indexData['index_permissions'] = implode( ',', $indexData['index_permissions'] );
|
||||
$indexData['index_tags'] = $indexData['index_tags'] ? implode( ',', $indexData['index_tags'] ) : NULL;
|
||||
return $indexData;
|
||||
}, $return['hits']['hits'] ), $return['hits']['total'] <= \IPS\Settings::i()->search_index_maxresults ? $return['hits']['total'] : (int) \IPS\Settings::i()->search_index_maxresults );
|
||||
}, $return['hits']['hits'] ), $total <= \IPS\Settings::i()->search_index_maxresults ? $total : (int) \IPS\Settings::i()->search_index_maxresults );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user