Существует несоответствие между результатом совпадения и точным соответствием - PullRequest
1 голос
/ 09 марта 2012

Существует несоответствие между оценкой совпадения с подстановочными символами и точным совпадением

Я ищу

recording:live OR recording:luve* 

А вот объяснительный вывод из поиска

DocNo:0:1.4196585:11111111-1cf0-4d1f-aca7-2a6f89e34b36
1.4196585 = (MATCH) max plus 0.1 times others of:
  0.3763506 = (MATCH) ConstantScore(recording:luve*), product of:
    1.0 = boost
    0.3763506 = queryNorm
  1.3820235 = (MATCH) weight(recording:luve in 0), product of:
    0.7211972 = queryWeight(recording:luve), product of:
      1.9162908 = idf(docFreq=1, maxDocs=5)
      0.3763506 = queryNorm
    1.9162908 = (MATCH) fieldWeight(recording:luve in 0), product of:
      1.0 = tf(termFreq(recording:luve)=1)
      1.9162908 = idf(docFreq=1, maxDocs=5)
      1.0 = fieldNorm(field=recording, doc=0)

DocNo:1:0.3763506:22222222-1cf0-4d1f-aca7-2a6f89e34b36
0.3763506 = (MATCH) max plus 0.1 times others of:
  0.3763506 = (MATCH) ConstantScore(recording:luve*), product of:
    1.0 = boost
    0.3763506 = queryNorm

В моем тесте у меня 5 документов, один из которых содержит точное совпадение, другой - подстановочный знак, а остальные три не соответствуют всем. Результат точного совпадения составляет 1,4 по сравнению с 0,37 для сопоставления с подстановочными знаками, что почти в 4 раза. При гораздо большем индексе оценка точного соответствия по редкому термину по сравнению с поиском по шаблону будет еще выше.

Вся разница связана с тем, что для точного соответствия используется подстановочный механизм, используемый для подстановочных знаков, подстановочные знаки не учитывают tf / idf или lengthnorm, вы просто получаете постоянную оценку за каждое совпадение. Теперь я не беспокоюсь о tf или lengthnorm в моей области данных, это не имеет большого значения, но счет idf является настоящим убийцей. Поскольку соответствующий документ найден один раз в 5 документах, его вклад в IDF равен квадрату IDF, т.е. 3,61

Я знаю, что эта постоянная оценка быстрее, чем вычисление tf * idf * lengthnorm для каждого совпадения с подстановочными знаками, но для меня не имеет смысла вносить такой большой вклад в счет. Я также знаю, что могу изменить метод перезаписи, но есть две проблемы с этим.

  1. Методы перезаписи со скорингом работают менее эффективно, потому что они вычисляют idf, tf и lengthnorm. idf - единственное значение, которое мне нужно.

  2. Те, кто действительно рассчитывают балл, тоже не имеют особого смысла, так как они вычисляют idf соответствующего термина, даже если это не то, что на самом деле искали, и этот термин может быть реже, чем то, что я действительно искал для, возможно, повышение его выше, чем точное совпадение.

(Я также мог бы изменить класс подобия, чтобы переопределить вычисление idf, чтобы оно всегда возвращало 1, но это не имеет смысла, потому что idf очень полезен для сравнения точных совпадений с разными словами

т.е. запись: luve ИЛИ запись: luve * ИЛИ запись: ИЛИ запись: *

Я бы хотел, чтобы совпадения с luve набирали больше, чем совпадения с общим словом the )

Так что метод перезаписи уже существует или можно просто рассчитать idf термина, которому он пытался соответствовать, например, в этом случае я ищу «luve» и подстановочный знак соответствует «luvely», что это умножит luvely совпадение на idf luve (3.61). Таким образом, мое совпадение с подстановочными знаками будет сравнимо с точным совпадением, и я могу просто изменить свой запрос, чтобы немного повысить точное совпадение, чтобы точное совпадение всегда получало больше совпадения с подстановочными знаками, но не слишком много

1047 * то есть *

recording:live^1.2 OR recording:luve* 

и с помощью этого мифического метода перезаписи это даст (в зависимости от queryNorm):

  • Док 0: 0: 1.692
  • Док. 1: 0: 1.419

Ответы [ 2 ]

0 голосов
/ 10 марта 2012

Хорошо, установив это как метод перезаписи для префиксных запросов, похоже, работает

public static class MultiTermUseIdfOfSearchTerm<Q extends Query> extends TopTermsRewrite<BooleanQuery> {

    //public static final class MultiTermUseIdfOfSearchTerm extends TopTermsRewrite<BooleanQuery> {
        private final Similarity similarity;

        /**
         * Create a TopTermsScoringBooleanQueryRewrite for
         * at most <code>size</code> terms.
         * <p>
         * NOTE: if {@link BooleanQuery#getMaxClauseCount} is smaller than
         * <code>size</code>, then it will be used instead.
         */
        public MultiTermUseIdfOfSearchTerm(int size) {
            super(size);
            this.similarity = new DefaultSimilarity();

        }

        @Override
        protected int getMaxSize() {
            return BooleanQuery.getMaxClauseCount();
        }

        @Override
        protected BooleanQuery getTopLevelQuery() {
            return new BooleanQuery(true);
        }

        @Override
        protected void addClause(BooleanQuery topLevel, Term term, float boost) {
            final Query tq = new ConstantScoreQuery(new TermQuery(term));
            tq.setBoost(boost);
            topLevel.add(tq, BooleanClause.Occur.SHOULD);
        }

        protected float getQueryBoost(final IndexReader reader, final MultiTermQuery query)
                throws IOException {
            float idf = 1f;
            float df;
            if (query instanceof PrefixQuery)
            {
                PrefixQuery fq = (PrefixQuery) query;
                df = reader.docFreq(fq.getPrefix());
                if(df>=1)
                {
                    idf = (float)Math.pow(similarity.idf((int) df, reader.numDocs()),2);
                }
            }
            return idf;
        }

        @Override
        public BooleanQuery rewrite(final IndexReader reader, final MultiTermQuery query) throws IOException {
            BooleanQuery  bq = (BooleanQuery)super.rewrite(reader, query);

            float idfBoost = getQueryBoost(reader, query);
            Iterator<BooleanClause> iterator = bq.iterator();
            while(iterator.hasNext())
            {
                BooleanClause next = iterator.next();
                next.getQuery().setBoost(next.getQuery().getBoost() * idfBoost);
            }
            return bq;
        }

    }
0 голосов
/ 09 марта 2012
...