public function findWithTenant($searchText, $tenantId, $sortDirection = 'desc') { $boolFilter = new Filter\Bool(); $boolFilter->addMust(new Filter\Term(['tenant.id' => $tenantId])); $boolQuery = new Query\Bool(); if ($searchText !== null) { $fieldQuery = new Query\MultiMatch(); $fieldQuery->setQuery("*" . $searchText . "*"); $fieldQuery->setFields(['name', 'description']); $boolQuery->addMust($fieldQuery); } $filtered = new Query\Filtered($boolQuery, $boolFilter); $query = Query::create($filtered); $query->addSort(['created_at' => $sortDirection]); return $this->findPaginated($query); }
public function publisherAction(Request $request, $page = 1) { $getTypes = $request->query->get('type_filters'); $typeFilters = !empty($getTypes) ? explode(',', $getTypes) : []; $publisherSearcher = $this->get('fos_elastica.index.search.publisher'); $boolQuery = new Query\Bool(); if (!empty($typeFilters)) { foreach ($typeFilters as $type) { $match = new Query\Match(); $match->setField('publisherType', $type); $boolQuery->addMust($match); } } $publisherQuery = new Query($boolQuery); $typeAgg = new Aggregation\Terms('types'); $typeAgg->setField('publisherType'); $typeAgg->setOrder('_term', 'asc'); $typeAgg->setSize(0); $publisherQuery->addAggregation($typeAgg); $adapter = new ElasticaAdapter($publisherSearcher, $publisherQuery); $pagerfanta = new Pagerfanta($adapter); $pagerfanta->setMaxPerPage(20); $pagerfanta->setCurrentPage($page); $publishers = $pagerfanta->getCurrentPageResults(); $types = $adapter->getResultSet()->getAggregation('types')['buckets']; $data = ['types' => $types, 'page' => 'ojs_site_explore_publisher', 'publishers' => $publishers, 'pagerfanta' => $pagerfanta, 'type_filters' => $typeFilters]; return $this->render('OjsSiteBundle:Explore:publisher.html.twig', $data); }
public function indexAction(Request $request, $page = 1) { $getTypes = $request->query->get('type_filters'); $getSubjects = $request->query->get('subject_filters'); $getPublishers = $request->query->get('publisher_filters'); $typeFilters = !empty($getTypes) ? explode(',', $getTypes) : []; $subjectFilters = !empty($getSubjects) ? explode(',', $getSubjects) : []; $publisherFilters = !empty($getPublishers) ? explode(',', $getPublishers) : []; $journalSearcher = $this->get('fos_elastica.index.search.journal'); $boolQuery = new Query\Bool(); $match = new Query\Match(); $match->setField('status', 1); $boolQuery->addMust($match); $match = new Query\Match(); $match->setField('published', true); $boolQuery->addMust($match); if (!empty($typeFilters) || !empty($subjectFilters) || !empty($publisherFilters)) { foreach ($typeFilters as $type) { $match = new Query\Match(); $match->setField('publisher.publisher_type.name', $type); $boolQuery->addMust($match); } foreach ($subjectFilters as $subject) { $match = new Query\Match(); $match->setField('subjects.subject', $subject); $boolQuery->addMust($match); } foreach ($publisherFilters as $publisher) { $match = new Query\Match(); $match->setField('publisher.name', $publisher); $boolQuery->addMust($match); } } $journalQuery = new Query($boolQuery); $typeAgg = new Aggregation\Terms('types'); $typeAgg->setField('publisher.publisher_type.name'); $typeAgg->setOrder('_term', 'asc'); $typeAgg->setSize(0); $journalQuery->addAggregation($typeAgg); $subjectAgg = new Aggregation\Terms('subjects'); $subjectAgg->setField('subjects.subject'); $subjectAgg->setOrder('_term', 'asc'); $subjectAgg->setSize(0); $journalQuery->addAggregation($subjectAgg); $publisherAgg = new Aggregation\Terms('publishers'); $publisherAgg->setField('publisher.name'); $publisherAgg->setOrder('_term', 'asc'); $publisherAgg->setSize(0); $journalQuery->addAggregation($publisherAgg); $adapter = new ElasticaAdapter($journalSearcher, $journalQuery); $pagerfanta = new Pagerfanta($adapter); $pagerfanta->setMaxPerPage(21); $pagerfanta->setCurrentPage($page); $journals = $pagerfanta->getCurrentPageResults(); $types = $adapter->getResultSet()->getAggregation('types')['buckets']; $subjects = $adapter->getResultSet()->getAggregation('subjects')['buckets']; $publishers = $adapter->getResultSet()->getAggregation('publishers')['buckets']; $data = ['types' => $types, 'subjects' => $subjects, 'publishers' => $publishers, 'type_filters' => $typeFilters, 'subject_filters' => $subjectFilters, 'publisher_filters' => $publisherFilters, 'journals' => $journals, 'pagerfanta' => $pagerfanta, 'page' => 'explore']; return $this->render('OjsSiteBundle:Explore:index.html.twig', $data); }
/** * search page index controller * * @param Request $request * @param int $page * @return \Symfony\Component\HttpFoundation\Response */ public function indexAction(Request $request, $page = 1) { /** * @var \Ojs\SearchBundle\Manager\SearchManager $searchManager */ $searchManager = $this->get('ojs_search_manager'); $getRoles = $request->query->get('role_filters'); $getSubjects = $request->query->get('subject_filters'); $getJournals = $request->query->get('journal_filters'); $roleFilters = !empty($getRoles) ? explode(',', $getRoles) : []; $subjectFilters = !empty($getSubjects) ? explode(',', $getSubjects) : []; $journalFilters = !empty($getJournals) ? explode(',', $getJournals) : []; $queryType = $request->query->has('type') ? $request->get('type') : 'basic'; $query = filter_var($request->get('q'), FILTER_SANITIZE_STRING); $section = filter_var($request->get('section'), FILTER_SANITIZE_STRING); $searcher = $this->get('fos_elastica.index.search'); $searchQuery = new Query('_all'); $boolQuery = new Query\Bool(); $match = new Query\Match(); $match->setField('status', 3); $boolQuery->addShould($match); $match = new Query\Match(); $match->setField('published', true); $boolQuery->addShould($match); //set query according to query type if ($queryType == 'basic') { $fieldQuery = new Query\MultiMatch(); $fieldQuery->setFields(['_all']); $fieldQuery->setQuery($query); $boolQuery->addMust($fieldQuery); } elseif ($queryType == 'advanced') { $parseQuery = $searchManager->parseSearchQuery($query); foreach ($parseQuery as $searchTerm) { $condition = $searchTerm['condition']; $advancedFieldQuery = new Query\MultiMatch(); $advancedFieldQuery->setFields([$searchTerm['searchField']]); $advancedFieldQuery->setQuery($searchTerm['searchText']); if ($condition == 'AND') { $boolQuery->addMust($advancedFieldQuery); } elseif ($condition == 'OR') { $boolQuery->addShould($advancedFieldQuery); } elseif ($condition == 'NOT') { $boolQuery->addMustNot($advancedFieldQuery); } } } elseif ($queryType == 'tag') { $matchQuery = new Query\Match(); $matchQuery->setField('tags', $query); $boolQuery->addMust($matchQuery); } //set aggregations if requested if (!empty($roleFilters) || !empty($subjectFilters) || !empty($journalFilters)) { foreach ($roleFilters as $role) { $match = new Query\Match(); $match->setField('user.userJournalRoles.role.name', $role); $boolQuery->addMust($match); } foreach ($subjectFilters as $subject) { $match = new Query\Match(); $match->setField('subjects', $subject); $boolQuery->addMust($match); } foreach ($journalFilters as $journal) { $match = new Query\Match(); $match->setField('user.userJournalRoles.journal.title', $journal); $boolQuery->addMust($match); } } //set our boolean query $searchQuery->setQuery($boolQuery); //get all result $searchQuery->setSize(1000); //get role aggregation $roleAgg = new Aggregation\Terms('roles'); $roleAgg->setField('userJournalRoles.role.name'); $roleAgg->setOrder('_term', 'asc'); $roleAgg->setSize(0); $searchQuery->addAggregation($roleAgg); //get subject aggregation $subjectAgg = new Aggregation\Terms('subjects'); $subjectAgg->setField('subjects'); $subjectAgg->setOrder('_term', 'asc'); $subjectAgg->setSize(0); $searchQuery->addAggregation($subjectAgg); //get journal aggregation $journalAgg = new Aggregation\Terms('journals'); $journalAgg->setField('journal.raw'); $journalAgg->setOrder('_term', 'asc'); $journalAgg->setSize(0); $searchQuery->addAggregation($journalAgg); /** * @var ResultSet $resultData */ $resultData = $searcher->search($searchQuery); $roles = $resultData->getAggregation('roles')['buckets']; $subjects = $resultData->getAggregation('subjects')['buckets']; $journals = $resultData->getAggregation('journals')['buckets']; if ($resultData->count() > 0) { /** * manipulate result data for easily use on template */ $results = $searchManager->buildResultsObject($resultData, $section); /** * if search section is not defined or empty redirect to first result section */ if (empty($section)) { $section = array_keys($results)[0]; $redirectParams = array_merge($request->query->all(), ['section' => $section]); return $this->redirectToRoute('ojs_search_index', $redirectParams); } else { /** * if section result is empty redirect to first that have result section */ if (!isset($results[$section])) { foreach ($results as $resultKey => $result) { if ($result['total_item'] > 0) { $redirectParams = array_merge($request->query->all(), ['section' => $resultKey]); return $this->redirectToRoute('ojs_search_index', $redirectParams); } } } } $adapter = new ArrayAdapter($results[$section]['data']); $pagerfanta = new Pagerfanta($adapter); $pagerfanta->setMaxPerPage(10); $pagerfanta->setCurrentPage($page); $results[$section]['data'] = $pagerfanta->getCurrentPageResults(); /** * add search query to query history * history data stores on session */ $this->addQueryToHistory($request, $query, $queryType, $resultData->count()); $data = ['results' => $results, 'query' => $query, 'queryType' => $queryType, 'section' => $section, 'total_count' => $searchManager->getTotalHit(), 'roles' => $roles, 'subjects' => $subjects, 'journals' => $journals, 'role_filters' => $roleFilters, 'subject_filters' => $subjectFilters, 'journal_filters' => $journalFilters, 'pagerfanta' => $pagerfanta]; } else { $data = ['query' => $query, 'queryType' => $queryType, 'total_count' => $searchManager->getTotalHit(), 'journals' => []]; } return $this->render('OjsSiteBundle:Search:index.html.twig', $data); }
public function testSearch() { $client = $this->_getClient(); $index = new Index($client, 'test'); $index->create(array(), true); $type = new Type($index, 'helloworld'); $doc = new Document(1, array('id' => 1, 'email' => '*****@*****.**', 'username' => 'hans', 'test' => array('2', '3', '5'))); $type->addDocument($doc); $doc = new Document(2, array('id' => 2, 'email' => '*****@*****.**', 'username' => 'emil', 'test' => array('1', '3', '6'))); $type->addDocument($doc); $doc = new Document(3, array('id' => 3, 'email' => '*****@*****.**', 'username' => 'ruth', 'test' => array('2', '3', '7'))); $type->addDocument($doc); // Refresh index $index->refresh(); $boolQuery = new Bool(); $termQuery1 = new Term(array('test' => '2')); $boolQuery->addMust($termQuery1); $resultSet = $type->search($boolQuery); $this->assertEquals(2, $resultSet->count()); $termQuery2 = new Term(array('test' => '5')); $boolQuery->addMust($termQuery2); $resultSet = $type->search($boolQuery); $this->assertEquals(1, $resultSet->count()); $termQuery3 = new Term(array('username' => 'hans')); $boolQuery->addMust($termQuery3); $resultSet = $type->search($boolQuery); $this->assertEquals(1, $resultSet->count()); $termQuery4 = new Term(array('username' => 'emil')); $boolQuery->addMust($termQuery4); $resultSet = $type->search($boolQuery); $this->assertEquals(0, $resultSet->count()); }
/** * @param string $search * @return BoolQuery */ private function getBoolQuery($search) { $bool = new BoolQuery(); $text = new Match(); $text->setField('text', $search); $bool->addMust($text); return $bool; }
/** * @param Request $request * @param int $page * @return \Symfony\Component\HttpFoundation\Response */ public function indexAction(Request $request, $page = 1) { $getRoles = $request->query->get('role_filters'); $getSubjects = $request->query->get('subject_filters'); $getJournals = $request->query->get('journal_filters'); $roleFilters = !empty($getRoles) ? explode(',', $getRoles) : []; $subjectFilters = !empty($getSubjects) ? explode(',', $getSubjects) : []; $journalFilters = !empty($getJournals) ? explode(',', $getJournals) : []; $userSearcher = $this->get('fos_elastica.index.search.user'); $userQuery = new Query('*'); if (!empty($roleFilters) || !empty($subjectFilters) || !empty($journalFilters)) { $boolQuery = new Query\Bool(); foreach ($roleFilters as $role) { $match = new Query\Match(); $match->setField('journalUsers.roles', $role); $boolQuery->addMust($match); } foreach ($subjectFilters as $subject) { $match = new Query\Match(); $match->setField('subjects', $subject); $boolQuery->addMust($match); } foreach ($journalFilters as $journal) { $match = new Query\Match(); $match->setField('journalUsers.journal.title', $journal); $boolQuery->addMust($match); } $userQuery->setQuery($boolQuery); } $roleAgg = new Aggregation\Terms('roles'); $roleAgg->setField('journalUsers.roles'); $roleAgg->setOrder('_term', 'asc'); $roleAgg->setSize(0); $userQuery->addAggregation($roleAgg); $subjectAgg = new Aggregation\Terms('subjects'); $subjectAgg->setField('subjects'); $subjectAgg->setOrder('_term', 'asc'); $subjectAgg->setSize(0); $userQuery->addAggregation($subjectAgg); $journalAgg = new Aggregation\Terms('journals'); $journalAgg->setField('journalUsers.journal.title'); $journalAgg->setOrder('_term', 'asc'); $journalAgg->setSize(0); $userQuery->addAggregation($journalAgg); $adapter = new ElasticaAdapter($userSearcher, $userQuery); $pagerfanta = new Pagerfanta($adapter); $pagerfanta->setMaxPerPage(20); $pagerfanta->setCurrentPage($page); $people = $pagerfanta->getCurrentPageResults(); $roles = $adapter->getResultSet()->getAggregation('roles')['buckets']; $subjects = $adapter->getResultSet()->getAggregation('subjects')['buckets']; $journals = $adapter->getResultSet()->getAggregation('journals')['buckets']; $data = ['people' => $people, 'roles' => $roles, 'subjects' => $subjects, 'journals' => $journals, 'pagerfanta' => $pagerfanta, 'role_filters' => $roleFilters, 'subject_filters' => $subjectFilters, 'journal_filters' => $journalFilters, 'page' => 'ojs_site_people_index']; return $this->render('OjsSiteBundle:People:index.html.twig', $data); }
/** * @param Search $search * @return Result[] */ public function search(Search $search) { $bool = new Bool(); $match = new Match(); $match->setField('text', $search->getInput()); $bool->addMust($match); $query = new Query(); $query->setQuery($bool); $query->setHighlight(['pre_tags' => ['<mark>'], 'post_tags' => ['</mark>'], 'fields' => ['text' => ['highlight_query' => [$bool->toArray()]]]]); $results = $this->getIndex()->search($query, 50)->getResults(); $this->onSearch($search, $results); return $results; }
/** * @param $q * @param $locale is verplicht * @return mixed */ public function search($q, $locale, $options = null) { $this->search->addIndex('plant'); $this->search->addType('plant'); /* Locale */ $locale_check = new Match(); $locale_check->setField("locale", $locale); /* The received query */ $query = new Query($q); /* Tie both queries together */ $bool = new Bool(); $bool->addShould($q); $bool->addShould($locale_check); $this->search->setQuery($bool); return $this->search->search($q, $options); }
/** * Filter search results so only documents that are viewable by the current user will be returned... * * @param \Elastica\Query\Bool $elasticaQueryBool */ protected function applySecurityContext($elasticaQueryBool) { $roles = array(); if (!is_null($this->securityContext)) { $user = $this->securityContext->getToken()->getUser(); if ($user instanceof BaseUser) { $roles = $user->getRoles(); } } // Anonymous access should always be available for both anonymous & logged in users if (!in_array('IS_AUTHENTICATED_ANONYMOUSLY', $roles)) { $roles[] = 'IS_AUTHENTICATED_ANONYMOUSLY'; } $elasticaQueryRoles = new \Elastica\Query\Terms(); $elasticaQueryRoles->setTerms('view_roles', $roles)->setMinimumMatch(1); $elasticaQueryBool->addMust($elasticaQueryRoles); }
/** * Perform a search on messages using Elasticsearch * * @param string $query The query string * @return Message[] The results of the search */ private function elasticSearch($query) { $finder = \Service::getContainer()->get('fos_elastica.finder.search'); $boolQuery = new Bool(); // We have only stored "active" messages and groups on Elasticsearch's // database, so there is no check for that again if ($this->player) { // Make sure that the parent of the message (i.e. the group that the // message belongs into) has the current player as its member $recipientQuery = new Term(); $recipientQuery->setTerm('members', $this->player->getId()); $parentQuery = new HasParent($recipientQuery, 'group'); $boolQuery->addMust($parentQuery); } $fieldQuery = new Match(); $fieldQuery->setFieldQuery('content', $query)->setFieldFuzziness('content', 'auto'); $boolQuery->addMust($fieldQuery); return $finder->find($boolQuery); }
/** * * @ApiDoc( * resource=true, * description="search users in username-email-tags and subjects (accepts regex inputs)", * parameters={ * { * "name"="q", * "dataType"="string", * "required"="true", * "description"="search term" * } * } * ) * @Get("/search/user") * * @param Request $request * @return array */ public function getUsersAction(Request $request) { $q = $request->get('q'); $search = $this->container->get('fos_elastica.index.search.user'); $s1 = new Query\Regexp(); $s1->setValue('username', $q); $s2 = new Query\Regexp(); $s2->setValue('subjects', $q); $s3 = new Query\Regexp(); $s3->setValue('tags', $q); $query = new Query\Bool(); $query->addShould($s1); $query->addShould($s2); $query->addShould($s3); $results = $search->search($query); $data = []; foreach ($results as $result) { $data[] = array_merge(array('id' => $result->getId()), $result->getData()); } return $data; }
/** * @param Request $request * @return JsonResponse */ public function autoCompleteAction(Request $request) { $q = filter_var($request->get('q'), FILTER_SANITIZE_STRING); $search = $this->get('fos_elastica.index.search.journal'); $searchQuery = new Query('_all'); $boolQuery = new Query\Bool(); $fieldQuery = new Query\MultiMatch(); $fieldQuery->setFields(['title']); $fieldQuery->setQuery(strtoupper($q)); $fieldQuery->setFuzziness(0.7); $boolQuery->addMust($fieldQuery); $searchQuery->setQuery($boolQuery); $searchQuery->setSize(10); $results = $search->search($searchQuery); $data = []; foreach ($results as $result) { $data[] = ['id' => $result->getId(), 'text' => $result->getData()['title']]; } return new JsonResponse($data); }
/** * @param $searchClosed * @return \Elastica\ResultSet * @throws Exception */ public function doSearch($searchClosed) { $this->connection = new ElasticSearchConnection(); $this->connection->init(); $this->whereClause = new Query\QueryString(); $this->whereClause->setQuery($this->searchTerms); $this->utility = new Util(); if (isset($_GET['page'])) { $this->currentPage = intval($_GET['page']); } $this->fieldMapping = $this->configurationManager->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'WMDB.Forger.SearchTermMapping'); $elasticaQuery = new Query(); if ($searchClosed === 'true') { $elasticaQuery->setQuery($this->whereClause); } else { $boolSearch = new Query\Bool(); $boolSearch->addMust($this->whereClause); $boolSearch->addMustNot(['term' => ['status.name' => 'Closed']]); $boolSearch->addMustNot(['term' => ['status.name' => 'Rejected']]); $boolSearch->addMustNot(['term' => ['status.name' => 'Resolved']]); $elasticaQuery->setQuery($boolSearch); } $elasticaQuery->setSize($this->perPage); $elasticaQuery->setFrom($this->currentPage * $this->perPage - $this->perPage); $usedFilters = $this->addFilters(); if ($usedFilters !== false) { $elasticaQuery->setPostFilter($usedFilters); } $this->addAggregations($elasticaQuery); $elasticaResultSet = $this->connection->getIndex()->search($elasticaQuery); $results = $elasticaResultSet->getResults(); $maxScore = $elasticaResultSet->getMaxScore(); $aggs = $elasticaResultSet->getAggregations(); $this->totalHits = $elasticaResultSet->getTotalHits(); $out = array('pagesToLinkTo' => $this->getPages(), 'currentPage' => $this->currentPage, 'prev' => $this->currentPage - 1, 'next' => $this->currentPage < ceil($this->totalHits / $this->perPage) ? $this->currentPage + 1 : 0, 'totalResults' => $this->totalHits, 'startingAtItem' => $this->currentPage * $this->perPage - ($this->perPage - 1), 'endingAtItem' => $this->currentPage * $this->perPage, 'results' => $results, 'maxScore' => $maxScore, 'aggs' => $aggs); if (intval($this->totalHits) <= intval($out['endingAtItem'])) { $out['endingAtItem'] = intval($this->totalHits); } return $out; }
/** * @param string[] $fields * @param string[] $nearMatchFields * @param string $queryString * @param string $nearMatchQuery * @return \Elastica\Query\Simple|\Elastica\Query\Bool */ private function buildSearchTextQuery(array $fields, array $nearMatchFields, $queryString, $nearMatchQuery) { $queryForMostFields = $this->buildSearchTextQueryForFields($fields, $queryString, $this->config->getElement('CirrusSearchPhraseSlop', 'default'), false); if ($nearMatchQuery) { // Build one query for the full text fields and one for the near match fields so that // the near match can run unescaped. $bool = new \Elastica\Query\Bool(); $bool->setMinimumNumberShouldMatch(1); $bool->addShould($queryForMostFields); $nearMatch = new \Elastica\Query\MultiMatch(); $nearMatch->setFields($nearMatchFields); $nearMatch->setQuery($nearMatchQuery); $bool->addShould($nearMatch); return $bool; } return $queryForMostFields; }
/** * Attach a common terms query to $parent with a should. * Note that if the all field is not used this can be more restrictive: * for the query word1 word2 both words would have to appear in the * same field. We cannot use similar techniques like cross_field of * QueryString with multiple fields which allows both words to be * in different fields. * * @param \Elastica\Query\Bool $parent * @param array $boostedFields of boostedFields * @param string $queryString the query * @param array $profile the profile */ private function attachCommonTermsClause(\Elastica\Query\Bool $parent, array $boostedFields, $queryString, $profile) { foreach ($boostedFields as $boostedField) { $parent->addShould($this->buildOneCommonTermsClause($boostedField, $queryString, $profile)); } }
/** * getQuery * * @access private * @return \Elastica\Query\AbstractQuery */ private function getQuery() { if (!$this->queryList) { return null; } if (count($this->queryList) == 1) { return current($this->queryList); } $query = new ElasticaQuery\Bool(); foreach ($this->queryList as $tmpQuery) { $query->addMust($tmpQuery); } return $query; }
/** * Powers full-text-like searches including prefix search. * * @param string $type * @param string $for * @return Status(mixed) results from the query transformed by the resultsType */ private function search($type, $for) { if ($this->nonTextQueries) { $bool = new \Elastica\Query\Bool(); if ($this->query !== null) { $bool->addMust($this->query); } foreach ($this->nonTextQueries as $nonTextQuery) { $bool->addMust($nonTextQuery); } $this->query = $bool; } if ($this->resultsType === null) { $this->resultsType = new FullTextResultsType(FullTextResultsType::HIGHLIGHT_ALL); } // Default null queries now so the rest of the method can assume it is not null. if ($this->query === null) { $this->query = new \Elastica\Query\MatchAll(); } $query = new Elastica\Query(); $query->setParam('_source', $this->resultsType->getSourceFiltering()); $query->setParam('fields', $this->resultsType->getFields()); $extraIndexes = array(); $indexType = $this->pickIndexTypeFromNamespaces(); if ($this->namespaces) { $extraIndexes = $this->getAndFilterExtraIndexes(); if ($this->needNsFilter($extraIndexes, $indexType)) { $this->filters[] = new \Elastica\Filter\Terms('namespace', $this->namespaces); } } // Wrap $this->query in a filtered query if there are any filters $unifiedFilter = Filters::unify($this->filters, $this->notFilters); if ($unifiedFilter !== null) { $this->query = new \Elastica\Query\Filtered($this->query, $unifiedFilter); } // Call installBoosts right after we're done munging the query to include filters // so any rescores installBoosts adds to the query are done against filtered results. $this->installBoosts(); $query->setQuery($this->query); $highlight = $this->resultsType->getHighlightingConfiguration($this->highlightSource); if ($highlight) { // Fuzzy queries work _terribly_ with the plain highlighter so just drop any field that is forcing // the plain highlighter all together. Do this here because this works so badly that no // ResultsType should be able to use the plain highlighter for these queries. if ($this->fuzzyQuery) { $highlight['fields'] = array_filter($highlight['fields'], function ($field) { return $field['type'] !== 'plain'; }); } if (!empty($this->nonTextHighlightQueries)) { // We have some phrase_prefix queries, so let's include them in the // generated highlight_query. $bool = new \Elastica\Query\Bool(); if ($this->highlightQuery) { $bool->addShould($this->highlightQuery); } foreach ($this->nonTextHighlightQueries as $nonTextHighlightQuery) { $bool->addShould($nonTextHighlightQuery); } $this->highlightQuery = $bool; } if ($this->highlightQuery) { $highlight['highlight_query'] = $this->highlightQuery->toArray(); } $query->setHighlight($highlight); } if ($this->suggest) { $query->setParam('suggest', $this->suggest); $query->addParam('stats', 'suggest'); } if ($this->offset) { $query->setFrom($this->offset); } if ($this->limit) { $query->setSize($this->limit); } if ($this->sort != 'relevance') { // Clear rescores if we aren't using relevance as the search sort because they aren't used. $this->rescore = array(); } if ($this->rescore) { // rescore_query has to be in array form before we send it to Elasticsearch but it is way easier to work // with if we leave it in query for until now $modifiedRescore = array(); foreach ($this->rescore as $rescore) { $rescore['query']['rescore_query'] = $rescore['query']['rescore_query']->toArray(); $modifiedRescore[] = $rescore; } $query->setParam('rescore', $modifiedRescore); } $query->addParam('stats', $type); switch ($this->sort) { case 'relevance': break; // The default // The default case 'title_asc': $query->setSort(array('title.keyword' => 'asc')); break; case 'title_desc': $query->setSort(array('title.keyword' => 'desc')); break; case 'incoming_links_asc': $query->setSort(array('incoming_links' => array('order' => 'asc', 'missing' => '_first'))); break; case 'incoming_links_desc': $query->setSort(array('incoming_links' => array('order' => 'desc', 'missing' => '_last'))); break; default: LoggerFactory::getInstance('CirrusSearch')->warning("Invalid sort type: {sort}", array('sort' => $this->sort)); } $queryOptions = array(); if ($this->config->get('CirrusSearchMoreAccurateScoringMode')) { $queryOptions['search_type'] = 'dfs_query_then_fetch'; } switch ($type) { case 'regex': $poolCounterType = 'CirrusSearch-Regex'; $queryOptions['timeout'] = $this->config->getElement('CirrusSearchSearchShardTimeout', 'regex'); break; case 'prefix': $poolCounterType = 'CirrusSearch-Prefix'; $queryOptions['timeout'] = $this->config->getElement('CirrusSearchSearchShardTimeout', 'default'); break; default: $poolCounterType = 'CirrusSearch-Search'; $queryOptions['timeout'] = $this->config->getElement('CirrusSearchSearchShardTimeout', 'default'); } $this->connection->setTimeout($queryOptions['timeout']); // Setup the search $pageType = $this->connection->getPageType($this->indexBaseName, $indexType); $search = $pageType->createSearch($query, $queryOptions); foreach ($extraIndexes as $i) { $search->addIndex($i); } $description = "{queryType} search for '{query}'"; $logContext = array('queryType' => $type, 'query' => $for); if ($this->returnQuery) { return Status::newGood(array('description' => $this->formatDescription($description, $logContext), 'path' => $search->getPath(), 'params' => $search->getOptions(), 'query' => $query->toArray(), 'options' => $queryOptions)); } // Perform the search $searcher = $this; $user = $this->user; $result = Util::doPoolCounterWork($poolCounterType, $this->user, function () use($searcher, $search, $description, $logContext) { try { $searcher->start($description, $logContext); return $searcher->success($search->search()); } catch (\Elastica\Exception\ExceptionInterface $e) { return $searcher->failure($e); } }, function ($error, $key, $userName) use($type, $description, $user, $logContext) { $forUserName = $userName ? "for {userName} " : ''; LoggerFactory::getInstance('CirrusSearch')->warning("Pool error {$forUserName}on key {key} during {$description}: {error}", $logContext + array('userName' => $userName, 'key' => 'key', 'error' => $error)); if ($error === 'pool-queuefull') { if (strpos($key, 'nowait:CirrusSearch:_per_user') === 0) { $loggedIn = $user->isLoggedIn() ? 'logged-in' : 'anonymous'; return Status::newFatal("cirrussearch-too-busy-for-you-{$loggedIn}-error"); } if ($type === 'regex') { return Status::newFatal('cirrussearch-regex-too-busy-error'); } return Status::newFatal('cirrussearch-too-busy-error'); } return Status::newFatal('cirrussearch-backend-error'); }); if ($result->isOK()) { $responseData = $result->getValue()->getResponse()->getData(); if ($this->returnResult) { return Status::newGood(array('description' => $this->formatDescription($description, $logContext), 'path' => $search->getPath(), 'result' => $responseData)); } $result->setResult(true, $this->resultsType->transformElasticsearchResult($this->suggestPrefixes, $this->suggestSuffixes, $result->getValue(), $this->searchContainedSyntax)); if (isset($responseData['timed_out']) && $responseData['timed_out']) { LoggerFactory::getInstance('CirrusSearch')->warning("{$description} timed out and only returned partial results!", $logContext); if ($result->getValue()->numRows() === 0) { return Status::newFatal('cirrussearch-backend-error'); } else { $result->warning('cirrussearch-timed-out'); } } } return $result; }
public function search() { //$finder = $this->container->get('fos_elastica.finder.search.articles'); $bool = new Query\Bool(); $multiMatch = new Query\MultiMatch(); $multiMatch->setFields(['subjects', 'title', 'keywords', 'subtitle', 'citations.raw', 'journal.title', 'journal.subtitle']); $multiMatch->setType('phrase_prefix'); $multiMatch->setQuery($this->getParam('term')); $bool->addMust($multiMatch); if ($this->filter) { foreach ($this->filter as $key => $filter) { $filterObj = new Query\Match(); $this->applyFilter($filterObj, $key, $filter); $bool->addMust($filterObj); } } $missing = new Filter\Missing("issue"); $not = new Filter\BoolNot($missing); $notQ = new Query\Filtered(); $notQ->setFilter($not); $bool->addMust($notQ); $query = new Query(); $query->setQuery($bool); $query->setFrom($this->getPage() * $this->getLimit()); $query->setSize($this->getLimit()); $aggregation = new Terms('journals'); $aggregation->setField('journal.id'); $aggregation->setOrder('_count', 'desc'); $qb = $this->em->createQueryBuilder(); $qb->select('count(r.id)')->from('OjsJournalBundle:Journal', 'r')->where($qb->expr()->eq('r.status', 3)); $aggregation->setSize($qb->getQuery()->getSingleScalarResult()); $query->addAggregation($aggregation); $aggregation = new Terms('authors'); $aggregation->setField('articleAuthors.author.id'); $aggregation->setOrder('_count', 'desc'); $qb = $this->em->createQueryBuilder(); $qb->select('count(r.id)')->from('OjsJournalBundle:Author', 'r'); $aggregation->setSize($qb->getQuery()->getSingleScalarResult()); $query->addAggregation($aggregation); $elasticaAdapter = new ElasticaAdapter($this->index, $query); $pagerFanta = new Pagerfanta($elasticaAdapter); $pagerFanta->setMaxPerPage($this->getLimit()); $pagerFanta->setCurrentPage($this->getPage()); /** @var ResultSet $search */ $search = $pagerFanta->getCurrentPageResults(); $result = $search->getResults(); //$search->getResults(); $this->pager = $pagerFanta; $transformer = new ElasticaToModelTransformer($this->registry, 'OjsJournalBundle:Article'); $transformer->setPropertyAccessor($this->propertyAccessor); $this->result = $transformer->transform($result); $this->setCount($pagerFanta->getNbResults()); $this->addAggregation('journal', $this->transform($search->getAggregation('journals')['buckets'], 'OjsJournalBundle:Journal')); $this->addAggregation('author', $this->transform($search->getAggregation('authors')['buckets'], 'OjsJournalBundle:Author')); return $this; }