Как этот запрос на присоединение к Solr 4.0 может вернуть больше результатов, чем запрос *:*?
Я столкнулся с очень странным поведением, которое я считаю ошибкой, но я могу ошибаться или неправильно понимать документацию, поэтому я спрашиваю.
У меня есть индекс SOLR и я работаю с новыми функциями версии 4.0.
Это код, который я использую (я использую расширение PECL SOLR):
<?
$options = array (
'hostname' => '192.168.200.31',
'path' => 'solr/slave',
);
$client = new SolrClient($options);
$query = new SolrQuery();
#$query->setQuery("{!join from=id to=med_id }type:medium");
$query->setQuery("*:*");
$query->addFilterQuery('type:product');
$query->addFilterQuery("product_type:tv_free");
$query_response = $client->query($query);
$response = $query_response->getResponse();
echo '<pre>'.print_r($response,true)."</pre>";
?>
Код выше возвращает 38296
документы. Однако, если я раскомментирую строку #$query->setQuery("*:*");
, так что запрос сейчас *:*
и эффективно соответствует каждому документу, я получаю 21867
документы возвращены - я думаю, что это правильный номер.
Если вы хотите узнать немного больше о сценарии использования и о том, что стоит за мыслями, вы можете читать дальше, но это всего лишь справочная информация:
Я индексирую два типа документов, которые я различаю по значению поля type
:
средний - в моем случае это фильм (например, аватар, касабланка и т. д.)
продукт - это предложения для фильмов, как DVD на Амазонке
Причиной этого разделения является то, что я хочу фильтровать / фасетные запросы, которые позволяют пользователю, например, искать:
- фильм, выпущенный в период с 1990 по 1955 год (эти метаданные хранятся в промежуточном документе)
- и это доступно на Amazon как DVD на 5% или меньше (эта информация хранится в документе продукта)
- и в названии фильма есть слово "джунгли" (хранится в промежуточном документе)
Я делаю поиск (используя dismax) по всем документам типа "средний" с "джунглями" в заголовке:
$query->setQuery("{!type=dismax qf='$qf' mm='1' q.alt='*:*'}jungle");
Затем я добавляю фильтр запросов следующим образом:
$query->addFilterQuery("{!join from=med_id to=id}provider:amazon");
$query->addFilterQuery("{!join from=med_id to=id}price:[0 TO 500]"); // price is in cents
$query->addFilterQuery("release_year:[1990 TO 1995]");
Обратите внимание, что мне нужны первые два запроса в качестве соединения с документами типа prdouct, у которых есть поле с именем med_id, которое содержит идентификатор документа носителя типа, связанного с ними.
Это все отлично работает! Тем не менее, я хочу, чтобы поиск по метаде проводился в документах типа product. Например, страна, где они доступны (где я могу заказать DVD)
Я получаю подсчет фасетов для всех полей, которые содержатся в средних документах из этой очереди, однако запросы на соединение не содержат никакой информации об исходных таблицах, используемых для фильтрации объединения с результатом. Итак, мне нужен второй запрос:
Я делаю то же самое, что и выше, но на этот раз я использую swap join, а не соединенные запросы:
Так что мой запрос dismax теперь становится запросом соединения:
$ query-> setQuery ("{! join from = id to = med_id} {! type = dismax qf = '$ qf' mm = '1' q.alt = ':'} jungle");
Мои присоединенные запросы фильтра становятся обычными запросами фильтра:
$query->addFilterQuery("provider:amazon");
$query->addFilterQuery("price:[0 TO 500]");
И мой обычный запрос фильтра становится объединенным - на этот раз от id поля до med_id:
$ query-> addFilterQuery ("! join from = id to = med_id} release_year: [1990 - 1995]");
Теперь это возвращает все продукты, которые соответствуют нашим фильтрам. Для одного носителя может быть более одного продукта - но я хочу, чтобы количество моих аспектов отражало количество фильмов, а не количество продуктов, поэтому я также сгруппировал по med_id и установил усечение для группы в значение true, например:
$query->addParam("group","true");
$query->addParam("group.field","med_id");
$query->addParam("group.truncate","true");
Единственная проблема заключается в том, что запрос на соединение, выполняющий поиск в средних полях, заставляет мой запрос каким-то образом возвращать больше результатов, а не меньше, что я сводил к минимальному коду в начале вопроса для воспроизведения.
1 ответ
Я думаю, что я обошел свою проблему, добавив свой запрос как фильтр, а не как запрос:
$query->addFilterQuery("{!join from=id to=med_id }{!type=dismax qf='$qf' mm='1' q.alt='*:*'}".$qs);
$query->setQuery("*:*");
Похоже, что это работает в небольших тестовых случаях, однако у меня все еще есть некоторые ошибки в моем хранилище данных, но мне нужно дважды проверить источники данных на наличие опасностей и создать тестовый случай, в котором я могу доказать разницу.
Мне также все еще интересно, почему возникают проблемы при установке в качестве запроса...
Редактировать:
Метод, описанный в этом ответе, эффективно решает проблему, однако я не уверен, почему он вообще существовал.
Однако эффект подсчета фасетов не является желательным, поскольку свертывание поля позволяет выполнять фасет только для наиболее релевантного документа в группе. Значение: без свертывания (группировки) счет может быть больше, чем фактический счетчик сред (поскольку может существовать несколько совпадающих продуктов). При свертывании может быть меньше (поскольку учитываются только значения одного документа). Таким образом, количество аспектов не будет работать таким образом. Единственное, что вы действительно знаете, какие значения фасетов будут возвращать как минимум 1 результат, и в зависимости от того, используете ли вы свертывание или нет, число, представляющее верхнюю и нижнюю границу, но не может быть фактическим числом результатов.