`
brandNewUser
  • 浏览: 446922 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Lucene根据字段进行自定义搜索扩展

阅读更多
最近需要对公司的产品搜索功能做一步改动,搜索到的结果首先按照是否有库存进行排序,然后再按照销量。由于库存量也是一个整数,如果直接按照库存量进行倒序排序的话,是不符合要求的,Lucene也没有支持我们这种特殊的业务需求,但是可以通过扩展的方式进行改写。
 
 
public class EmptyStockComparatorSource extends FieldComparatorSource {
    @Override
    public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed)
            throws IOException {
        return new LongComparator(numHits, fieldname, 0L);
    }

    public static class LongComparator extends FieldComparator.NumericComparator<Long> {
        private final long[] values;
        private long bottom;
        private long topValue;

        /**
         * Creates a new comparator based on {@link Long#compare} for {@code numHits}.
         * When a document has no value for the field, {@code missingValue} is substituted.
         */
        public LongComparator(int numHits, String field, Long missingValue) {
            super(field, missingValue);
            values = new long[numHits];
        }

        @Override
        protected void doSetNextReader(LeafReaderContext context) throws IOException {
            currentReaderValues = getNumericDocValues(context, field);
            if (missingValue != null) {
                docsWithField = getDocsWithValue(context, field);
                // optimization to remove unneeded checks on the bit interface:
                if (docsWithField instanceof Bits.MatchAllBits) {
                    docsWithField = null;
                }
            } else {
                docsWithField = null;
            }
        }

        @Override
        public int compare(int slot1, int slot2) {
            return Long.compare(values[slot1], values[slot2]);
        }

        @Override
        public int compareBottom(int doc) {
            // TODO: there are sneaky non-branch ways to compute
            // -1/+1/0 sign
            long v2 = currentReaderValues.get(doc);
            // Test for v2 == 0 to save Bits.get method call for
            // the common case (doc has value and value is non-zero):
            if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
                v2 = missingValue;
            }

            return Long.compare(bottom, v2);
        }

        @Override
        public void copy(int slot, int doc) {
            long v2 = currentReaderValues.get(doc);
            // Test for v2 == 0 to save Bits.get method call for
            // the common case (doc has value and value is non-zero):
            if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
                v2 = missingValue;
            }

            values[slot] = v2 > 0L ? 1L : 0L;
        }

        @Override
        public void setBottom(final int bottom) {
            this.bottom = values[bottom];
        }

        @Override
        public void setTopValue(Long value) {
            topValue = value;
        }

        @Override
        public Long value(int slot) {
            return Long.valueOf(values[slot]) ;
        }

        @Override
        public int compareTop(int doc) {
            long docValue = currentReaderValues.get(doc);
            // Test for docValue == 0 to save Bits.get method call for
            // the common case (doc has value and value is non-zero):
            if (docsWithField != null && docValue == 0 && !docsWithField.get(doc)) {
                docValue = missingValue;
            }
            return Long.compare(topValue, docValue);
        }
    }
}
 
 
其中LongComparator直接从lucene源码中copy出来,只需要做些许修改即可,最主要的修改就是copy(int slot, int doc)方法,在复制比较值得过程中,将所有存在库存的值都视为1,否则视为0,这样排序的结果就是我们所期待的。
 
我们用到的测试用例:
 
Directory directory1 = FSDirectory.open(Paths.get(
                "/Users/xxx/develop/tools/solr-5.5.0/server/solr/product/data/index"));
        DirectoryReader directoryReader1 = DirectoryReader.open(directory1);
        IndexSearcher searcher1 = new IndexSearcher(directoryReader1);
        Sort sort1 = new Sort(new SortField("psfixstock", new EmptyStockComparatorSource(), true),
                new SortField("salesVolume", SortField.Type.INT, true));

        TopFieldDocs topDocs1 = searcher1.search(new TermQuery(new Term("gender_text", "女士")), 10, sort1);
        for (ScoreDoc scoreDoc : topDocs1.scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = searcher1.doc(doc);
            System.out.println(String.format("docId=%s, psfixstock=%s, salesVolumn=%s", doc, document.get("psfixstock"), document.get("salesVolume")));
        }
 
 
在排序时,需要将其加入至Sort对象中,但执行的时候出现错误,显示docvalues的类型不正确:
 
Exception in thread "main" java.lang.IllegalStateException: unexpected docvalues type NONE for field 'psfixstock' (expected=NUMERIC). Use UninvertingReader or index with docvalues.
    at org.apache.lucene.index.DocValues.checkField(DocValues.java:208)
    at org.apache.lucene.index.DocValues.getNumeric(DocValues.java:227)
    at org.apache.lucene.search.FieldComparator$NumericComparator.getNumericDocValues(FieldComparator.java:167)
    at com.zp.solr.handler.component.EmptyStockComparatorSource$LongComparator.doSetNextReader(EmptyStockComparatorSource.java:36)
    at org.apache.lucene.search.SimpleFieldComparator.getLeafComparator(SimpleFieldComparator.java:36)
    at org.apache.lucene.search.FieldValueHitQueue.getComparators(FieldValueHitQueue.java:183)
    at org.apache.lucene.search.TopFieldCollector$SimpleFieldCollector.getLeafCollector(TopFieldCollector.java:164)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:812)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:535)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:744)
    at org.apache.lucene.search.IndexSearcher.searchAfter(IndexSearcher.java:729)
    at org.apache.lucene.search.IndexSearcher.searchAfter(IndexSearcher.java:671)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:577)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:627)
    at com.zp.solr.handler.component.EmptyStockSortingTest.main(EmptyStockSortingTest.java:57)
 
经过一番查找,找到原因,参考文档:http://qindongliang.iteye.com/blog/2297280,我们搜索所使用到的字段没有设置对应的docType。如果在solr中,需要进行手动排序的字段,设置docValues=“true”,并进行重新索引(使用full-import方式):
 
   
<field name="psfixstock" type="tint" indexed="true" stored="true" multiValued="false" docValues="true" />
 
 
必须要重新建立索引才可以正常运行。注意,此时Solr与Elastic Search采取的方案有所不同,Solr默认docValues=false,而ES则相反,使用Doc索引方式会对性能产生一定的影响,要谨慎使用。
 
对于lucene中,需要将添加document中增加数字类型Field:NumericDocValuesField,否则出现上面的错误,
 
document.add(new NumericDocValuesField("stock", stock));
 
 
最终的排序结果已经按照我们的需要进行了:
 
docId=2629, psfixstock=98391, salesVolumn=4685
docId=305, psfixstock=991, salesVolumn=14
docId=16762, psfixstock=3, salesVolumn=12
docId=22350, psfixstock=993, salesVolumn=10
docId=29021, psfixstock=11076, salesVolumn=10
docId=3635, psfixstock=61, salesVolumn=6
docId=4111, psfixstock=1104, salesVolumn=5
docId=10608, psfixstock=4395, salesVolumn=5
docId=4874, psfixstock=4975, salesVolumn=4
docId=4911, psfixstock=6, salesVolumn=4
docId=15071, psfixstock=998, salesVolumn=4
docId=4837, psfixstock=9, salesVolumn=3
docId=4860, psfixstock=1002, salesVolumn=3
docId=3749, psfixstock=2240, salesVolumn=2
docId=4109, psfixstock=1493, salesVolumn=2
docId=15068, psfixstock=1000, salesVolumn=2
docId=25901, psfixstock=11110, salesVolumn=2
docId=3688, psfixstock=21, salesVolumn=1
docId=4912, psfixstock=17, salesVolumn=1
docId=5035, psfixstock=2, salesVolumn=1
docId=11835, psfixstock=8, salesVolumn=1
docId=12044, psfixstock=1, salesVolumn=1
docId=13508, psfixstock=2, salesVolumn=1
docId=20019, psfixstock=1, salesVolumn=1
docId=20884, psfixstock=100000, salesVolumn=1
docId=22620, psfixstock=1, salesVolumn=1
docId=24128, psfixstock=1, salesVolumn=1
docId=0, psfixstock=2, salesVolumn=0
docId=9, psfixstock=1, salesVolumn=0
docId=11, psfixstock=4, salesVolumn=0
docId=15, psfixstock=3, salesVolumn=0
docId=20, psfixstock=4, salesVolumn=0
docId=23, psfixstock=2, salesVolumn=0
docId=24, psfixstock=5, salesVolumn=0
docId=25, psfixstock=7, salesVolumn=0
docId=35, psfixstock=2, salesVolumn=0
docId=53, psfixstock=2, salesVolumn=0
 
 
 
 
分享到:
评论

相关推荐

    lucene 自定义评分

    lucene 自定义评分 实现 增加自定义的权重

    lucene自定义排序实现

    lucene自定义排序实现,大家有兴趣关注我的博客http://blog.csdn.net/wuyinggui10000/article/category/3173543

    Lucene5学习之自定义Collector

    NULL 博文链接:https://iamyida.iteye.com/blog/2202111

    Lucene5学习之自定义同义词分词器简单示例

    NULL 博文链接:https://iamyida.iteye.com/blog/2197355

    Lucene5学习之自定义排序

    NULL 博文链接:https://iamyida.iteye.com/blog/2201372

    lucene 多字段查询+文字高亮显示

    NULL 博文链接:https://navylee.iteye.com/blog/740128

    C#+Lucene.Net开发完成的一个自定义WEB搜索引擎

    C#+Lucene.Net开发完成的一个自定义WEB搜索引擎,本项目实现了分词、模糊索引,加以Lucene.Net内部核心功能共同实现了搜索机制引擎

    lucene的应用程序扩展

    这里是我搜集的一些关于asp.net 所需要的 lucene.net 的一些*.dll 应用程序扩展

    利用lucene进行搜索

    利用lucene进行搜索,IndexSearcher是整个Lucene搜索查询相关信息的驱动引擎,在使IndexSearcher之前,需要构建IndexSearcher对象,Lucene提供了两种构建IndexSearcher对象的方式: 1、基于Directory对象构建; 2...

    java Lucene 中自定义排序的实现

    Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在...

    如何使用Lucene的中文分词搜索

    NULL 博文链接:https://gznofeng.iteye.com/blog/1129902

    使用Lucene.net进行全文搜索

    使用Lucene.net进行全文查找多关键字匹配

    lucene排序.zip

    Lucene根据关键词出现次数排序以及自定义排序,可以自定义优先级,包含list字段排序与pom等

    lucene实例lucene实例

    lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例

    Lucene实战

    从Lucene核心、Lucene应用、案例分析3个方面详细系统地介绍了Lucene,包括认识Lucene、建立索引、为应用程序添加搜索功能、高级搜索技术、扩展搜索、使用Tika提取文本、Lucene的高级扩展、使用其他编程语言访问...

    Lucene in Action 中文版

    《Lucene实战 第2版 》基于Apache的Lucene 3 0 从Lucene核心 Lucene应用 案例分析3个方面详细系统地介绍了Lucene 包括认识Lucene 建立索引 为应用程序添加搜索功能 高级搜索技术 扩展搜索 使用Tika提取文本 Lucene的...

    Lucene 3.6 学习笔记

    第六章 LUCENE扩展 54 6.1 Luke 54 (1) 启动Luke 54 (2) 索引概述页面 55 (3) 查看索引信息 56 (4) 查询索引信息 57 6.2 Tika 58 (1) Tika的使用 58 (2) Tika的原理 59 6.3 高亮显示 61 (1) 自定义高亮标签 61 (2) ...

    java(结合lucene)版的公交搜索系统

    java(结合lucene)版的公交搜索系统 java(结合lucene)版的公交搜索系统 java(结合lucene)版的公交搜索系统 java(结合lucene)版的公交搜索系统 java(结合lucene)版的公交搜索系统 java(结合lucene)版的公交搜索系统 ...

    lucene去重、分组统计

    用到的工具 jsoup+spring+struct+DButil+mysql+lucene 可以配置采集网站的图片,包含分组统计,相同数据合并功能,主要是给群内成员来个demo,让大家有个学习的demo 小试牛刀、临时写的,莫吐槽 需要用到mysql...

    lucene,lucene教程,lucene讲解

    为了对文档进行索引,Lucene 提供了五个基础的类 public class IndexWriter org.apache.lucene.index.IndexWriter public abstract class Directory org.apache.lucene.store.Directory public abstract class ...

Global site tag (gtag.js) - Google Analytics