Как получить диапазоны граней в результатах solr?

Предположим, у меня есть поле под названием цена для документов в Solr, и это поле фасетировано. Я хочу получить фасеты в виде диапазонов значений (например: 0-100, 100-500, 500-1000 и т. д.). Как это сделать?

Я могу указать диапазоны заранее, но я также хочу знать, возможно ли вычислить диапазоны (скажем, для 5 значений) автоматически на основе значений в документах?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
15
0
27 649
4

Ответы 4

Вполне может быть лучший ответ для Solr, но я работаю с прямым Lucene, и, поскольку вы не получаете особой тяги, я возьму удар. Там я бы создал заполненный Filter с FilteredQuery, обернув исходный Query. Тогда я бы купил FieldCache для интересующей области. Перечислите попадания в битовом наборе фильтра, и для каждого попадания вы получите значение поля из кеша полей и добавите его в SortedSet. Когда у вас есть все совпадения, разделите размер набора на количество диапазонов, которое вы хотите (от пяти до семи - хорошее число в соответствии с пользовательским интерфейсом, ребята), и вместо однозначного ограничения ваши фасеты будут быть запросом диапазона с нижней и верхней границами каждого из этих подмножеств.

Я бы рекомендовал использовать логику особых случаев для небольшого числа значений; очевидно, что если у вас есть только четыре различных значения, нет смысла пытаться сделать из них 5 уточнений диапазона. Ниже определенного порога (скажем, 3 * ваше идеальное количество диапазонов) вы просто обычно показываете фасеты, а не диапазоны.

Чтобы ответить на ваш первый вопрос, вы можете получить диапазоны фасетов, используя общую поддержку фасетных запросов. Пример Здесь:

http://localhost:8983/solr/select?q=video&rows=0&facet=true&facet.query=price:[*+TO+500]&facet.query=price:[500+TO+*]

Что касается вашего второго вопроса (автоматически предлагающего диапазоны фасетов), он еще не реализован. Некоторые утверждают, что этот вид запросов лучше всего реализовать в вашем приложении, а не позволять Solr «угадывать» наилучшие диапазоны фасетов.

Вот несколько дискуссий по теме:

Может быть, на вечеринку опоздаешь на шесть лет, но ссылки больше не работают.

Bucket 07.07.2014 21:32

@DesertIvy Обязательно найдите их на archive.org или где-нибудь еще и отредактируйте ответ.

Mauricio Scheffer 08.07.2014 00:37

Вау, даже не знал, что это существует. Отличный инструмент!

Bucket 08.07.2014 00:58

Вы можете использовать диапазоны фасетов solr

http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range

Я разработал, как рассчитать разумные динамические аспекты для диапазонов цен на продукты. Решение включает в себя некоторую предварительную обработку документов и некоторую пост-обработку результатов запроса, но для этого требуется только один запрос к Solr, и он должен работать даже в старой версии Solr, например 1.4.

Округляйте цены перед отправкой

Во-первых, перед отправкой документа округлять от цены до ближайшей «красивой круглой границы фасета» и сохраните ее в поле «rounded_price». Пользователям нравится, чтобы их грани выглядели как «250-500», а не «247-483», и округление также означает, что вы получаете обратно сотни ценовых аспектов, а не миллионы из них. Приложив некоторые усилия, следующий код можно обобщить для удобного округления при любой ценовой шкале:

    public static decimal RoundPrice(decimal price)
    {
        if (price < 25)
            return Math.Ceiling(price);
        else if (price < 100)
            return Math.Ceiling(price / 5) * 5;
        else if (price < 250)
            return Math.Ceiling(price / 10) * 10;
        else if (price < 1000)
            return Math.Ceiling(price / 25) * 25;
        else if (price < 2500)
            return Math.Ceiling(price / 100) * 100;
        else if (price < 10000)
            return Math.Ceiling(price / 250) * 250;
        else if (price < 25000)
            return Math.Ceiling(price / 1000) * 1000;
        else if (price < 100000)
            return Math.Ceiling(price / 2500) * 2500;
        else
            return Math.Ceiling(price / 5000) * 5000;
    }

Допустимые цены: 1,2,3, ..., 24,25,30,35, ..., 95,100,110, ..., 240,250,275,300,325, ..., 975,1000 и так далее.

Получите все аспекты по округленным ценам

Во-вторых, при отправке запроса запросите все аспекты округленных цен, отсортированных по цене: facet.field=rounded_price. Благодаря округлению вы получите не более нескольких сотен граней.

Объедините смежные грани в более крупные грани

В-третьих, после того, как у вас есть результаты, пользователь хочет видеть только от 3 до 7 аспектов, а не сотни аспектов. Итак, объедините смежные фасеты в несколько больших фасетов (называемых «сегментами»), пытаясь получить примерно равное количество документов в каждом сегменте. Следующий, более сложный код делает это, возвращая кортежи (начало, конец, счет), подходящие для выполнения запросов диапазона. Возвращенные значения будут правильными при условии, что цены были округлены вверх до ближайшей границы:

    public static List<Tuple<string, string, int>> CombinePriceFacets(int nSegments, ICollection<KeyValuePair<string, int>> prices)
    {
        var ranges = new List<Tuple<string, string, int>>();
        int productCount = prices.Sum(p => p.Value);
        int productsRemaining = productCount;
        if (nSegments < 2)
            return ranges;
        int segmentSize = productCount / nSegments;
        string start = "*";
        string end = "0";
        int count = 0;
        int totalCount = 0;
        int segmentIdx = 1;
        foreach (KeyValuePair<string, int> price in prices)
        {
            end = price.Key;
            count += price.Value;
            totalCount += price.Value;
            productsRemaining -= price.Value;
            if (totalCount >= segmentSize * segmentIdx)
            {
                ranges.Add(new Tuple<string, string, int>(start, end, count));
                start = end;
                count = 0;
                segmentIdx += 1;
            }
            if (segmentIdx == nSegments)
            {
                ranges.Add(new Tuple<string, string, int>(start, "*", count + productsRemaining));
                break;
            }
        }
        return ranges;
    }

Фильтровать результаты по выбранному аспекту

В-четвертых, предположим, что («250», «500», 38) был одним из результирующих сегментов. Если пользователь выбирает «от 250 до 500 долларов» в качестве фильтра, просто выполните запрос фильтра fq=price:[250 TO 500].

Другие вопросы по теме