当前位置: 首页 > 知识库问答 >
问题:

在Lucene 4中允许对数值字段进行范围查询的最简单方法

冯奇思
2023-03-14

我正在重新访问最初为Lucene 3.0编写的代码(然后我更新了它,使其适用于4.0,但尚未利用所有4.0改进)。

对于我希望能够进行范围查询的数字字段,我将字段添加到文档中,如下所示:

BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
NumericUtils.intToPrefixCoded(value, 0, bytes);
doc.add(new Field(fieldname, bytes.utf8ToString(),
    new FieldType(StringField.TYPE_NOT_STORED)));

然后我必须有一个自定义查询解析器覆盖方法newTermQuery()和新RangeQuery()

public class ReleaseQueryParser extends MultiFieldQueryParser
{

    public ReleaseQueryParser(String[] strings, Analyzer a)
    {
        super(LuceneVersion.LUCENE_VERSION, strings, a);
    }

    protected Query newTermQuery(Term term)
    {
        if (
                (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            try
            {

                int number = Integer.parseInt(term.text());
                BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
                NumericUtils.intToPrefixCoded(number, 0, bytes);
                TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString()));
                return tq;
            }
            catch (NumberFormatException nfe)
            {
                //If not provided numeric argument just leave as is, won't give matches
                return super.newTermQuery(term);
            }
        }
        else
        {
            return super.newTermQuery(term);

        }
    }

    @Override
    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean startInclusive,
                               boolean endInclusive)
    {
        if (
                (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            BytesRef bytes1 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            BytesRef bytes2 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part1), 0, bytes1);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part2), 0, bytes2);
            part1 = bytes1.utf8ToString();
            part2 = bytes2.utf8ToString();
        }
        TermRangeQuery query = (TermRangeQuery)
                super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
        return query;

    }
}

我一直认为这段代码相当笨拙,不知道现在是否可以简化一些?

最新消息

尝试按如下方式使用IntField

doc.add(new IntField(field.getName(),value,new FieldType(StringField.TYPE_NOT_STORED)));

编译好了,但是我的索引构建测试方法

Fields fields = MultiFields.getFields(ir);
Terms terms = fields.terms(field.getName());
TermsEnum termsEnum = terms.iterator(null);
termsEnum.next();
assertEquals(value, NumericUtils.prefixCodedToInt(termsEnum.term()));

因条款上的NullPointerException而失败。迭代器()行。

改为

doc.add(new IntField(field.getName(), value, new FieldType(IntField.TYPE_NOT_STORED)));

这很管用,但令我惊讶的是

NumericUtils.prefixCodedToInt(termsEnum.term())

仍然有效,我想IntField只是我最初拥有的ByteRef代码的包装器。

然后重写QueryParser如下

public class ReleaseQueryParser extends MultiFieldQueryParser
{

    public ReleaseQueryParser(String[] strings, Analyzer a)
    {
        super(LuceneVersion.LUCENE_VERSION, strings, a);
    }

    protected Query newTermQuery(Term term)
    {
        if (
                (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            return NumericRangeQuery.newIntRange(term.field(), Integer.parseInt(term.text()), Integer.parseInt(term.text()), true, true);
        }
        else
        {
            return super.newTermQuery(term);

        }
    }

    @Override
    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean startInclusive,
                               boolean endInclusive)
    {
        if (
                (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2),startInclusive, endInclusive);
        }
        else
        {
            return super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
        }
    }
}

这是可行的,我并不想在newTermQuery(术语)中使用范围查询,但我找不到更简单的方法。

共有1个答案

田鸿彩
2023-03-14

使用lucene提供的IntFieldLongField类。然后,您可以使用指定类型的标准numeriRangeQuery查询索引

 类似资料:
  • 我有一个用Swagger描述的POSTendpoint,我希望这个endpoint也有查询参数。我们使用1.2 swagger格式是因为传统原因。我们使用3scale,它托管文档,您可以在他们的web UI中编辑您的swagger。然而,当我试图保存文档时,它给我以下错误。 < code>JSON规范不能在同一方法上有paramType='body '和param type = ' query '

  • 本文向大家介绍ThinkPHP查询返回简单字段数组的方法,包括了ThinkPHP查询返回简单字段数组的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了ThinkPHP查询返回简单字段数组的方法,是ThinkPHP程序设计中一个很实用的功能。具体方法如下: 通常来说使用select语句。返回的都是结构较复杂的字段数组。如以下是一个简单的查询: 查询后,得到的结果是: 从结构就看出这是结构

  • 问题内容: 假设我们有一个这样的数据库: Project_tbl: personel_project_tbl: instrument_project_tbl: 现在,我需要对项目列表进行排序,并根据它们与项目A的相似性对其进行排名。 例如: A和B在3个用户中共有1个用户,在2个工具中有2个用户,因此它们的相似度排名是(1/2 + 2/2)/ 2 = 75% A和C没有共同的用户,但拥有2台以上的

  • 问题内容: 我希望能够查询文本,但也只能检索数据中某个整数字段的最大值的结果。我已经阅读了有关聚合和过滤器的文档,但我不太清楚自己在寻找什么。 例如,我有一些重复的数据得到索引,除了整数字段外,这些数据都是相同的-我们称这个字段为。 因此,作为示例,给定将这些数据放入elasticsearch中: 如果我查询 我会得到4个结果。我想要一个过滤器,这样我只能得到两个结果-仅包含具有最大字段的项目。

  • 问题内容: 我有一个Google Spreadsheet,我想运行一个函数。但是我希望该语句检查一系列值。我基本上是在寻找要在SQL中使用的语句-Google Spreadsheets中的等效语句是什么?所以现在我有: 那行得通。但是我真正需要的是: 当然,该声明会失败。如何获得一系列值的位置?这些是文本值,如果有区别的话。 问题答案: 大招Zolley!这是一个小改进。 代替: = CONCAT

  • 可以对模型的查询和写入操作进行封装,例如: <?php namespace app\index\model; use think\Model; class User extends Model { public function scopeThinkphp($query) { $query->where('name','thinkphp')->field('i