`
brandNewUser
  • 浏览: 456925 次
  • 性别: 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自定义排序实现

    在搜索引擎技术中,Apache Lucene ...总的来说,理解并掌握 Lucene 自定义排序是提升搜索体验的关键,它使我们能够根据业务需求灵活地调整搜索结果的呈现方式。通过实践和学习,你可以创建出更符合用户需求的搜索引擎。

    lucene 自定义评分

    总之,Lucene 的自定义评分机制提供了一种强大的工具,让我们可以根据业务需求灵活调整搜索结果的排序。通过深入理解评分机制并有效地利用自定义评分,我们可以构建出更符合用户期望的搜索系统,提升用户体验。在...

    lucene的应用程序扩展

    这可能涉及到使用 Lucene 提供的 Field 类来定义字段,以及选择合适的分析器对文本进行预处理。 标签中的“lucene .dll”强调了 Lucene 库的核心组成部分,DLL 文件是 .NET 应用程序中模块化代码的载体。在 Lucene...

    lucene 高级搜索项目

    **Lucene 高级搜索项目概述** Lucene 是一个高性能、全文检索库,它提供了文本分析、索引和搜索功能,被广泛应用于各种搜索引擎的构建。在这个“Lucene 高级搜索项目”中,我们将深入探讨如何利用Lucene实现附件...

    lucene3.6 搜索例子

    Apache Lucene 是一个开源全文搜索引擎库,为开发者提供了在Java应用程序中实现高效、可扩展的搜索功能的工具。在本篇文章中,我们将深入探讨Lucene 3.6版本中的搜索功能,通过实例解析其核心概念和操作流程。 一、...

    Lucene group by ,分组实现

    在搜索引擎和信息检索领域,Apache Lucene 是一个广泛使用的全文索引库,它提供了高效、可扩展的搜索功能。在处理大量数据时,有时我们需要对搜索结果进行分组,以便更好地理解和分析数据。"Lucene group by" 指的...

    lucene 4.7.2 Demo

    在4.7.2版本中,Lucene引入了通用对象搜索,这意味着你可以根据自定义的对象类型进行搜索,这极大地扩展了Lucene的应用场景。 范围搜索是Lucene的另一个亮点,允许用户按数值或日期范围进行过滤。例如,你可以搜索...

    lucene

    3. 高级搜索特性:支持多字段搜索、过滤器查询、自定义评分函数等。 五、实际应用 Lucene常与其他框架结合使用,如Spring Data Solr、Hibernate Search等,实现企业级搜索解决方案。同时,它也被用于搜索引擎开发、...

    lucene3.6.1文件关键字搜索代码(附加核心包)

    4. **排序和评分**:Lucene支持对搜索结果进行排序,既可以按照相关性(由TF-IDF等算法计算得出的评分)排序,也可以按照其他自定义字段排序。 5. **扩展性**:Lucene允许开发者添加自定义的分析器、过滤器和查询...

    lucene开发WEB搜索引擎

    《使用LUCENE.NET构建WEB搜索引擎》 在信息化飞速发展的今天,搜索引擎已经成为人们获取网络信息的重要工具。本文将深入探讨如何使用LUCENE.NET框架来开发一款基于C#的WEB搜索引擎,帮助开发者掌握这一核心技术。 ...

    apache下的lucene教程

    - **基本查询**:了解如何使用Lucene进行简单的文本匹配查询。 - **高级查询技术**:包括布尔查询、短语查询、范围查询等多种复杂的查询方式。 - **查询优化**:讨论提高查询效率的方法,如缓存机制、查询重写等。 ...

    Lucene.Net站内搜索

    **正文** 《Lucene.Net站内搜索:打造高效搜索引擎》 在互联网信息爆炸的时代,站内搜索成为网站提供用户体验的...同时,Lucene.Net的灵活性和可扩展性使得搜索功能可以根据实际需求进行定制,适应各种复杂的场景。

    lucene-4.7.0全套jar包

    - **文档增强**:扩展了文档模型,支持更多的元数据和自定义字段类型。 在实际应用中,Lucene 4.7.0的JAR包通常会包含以下组件: - **Core模块**:这是Lucene的核心,包含了索引和搜索的基本功能,如`lucene-core-...

    Lucene.NET全文索引搜索Demo项目

    7. **扩展性**:Lucene.NET设计为模块化,可以方便地集成到各种应用程序中,同时通过插件机制可以扩展其功能,如自定义分词器、过滤器等。 通过这个Demo项目,开发者可以学习如何在.NET项目中集成全文搜索功能,...

    lucene 网页抓取,模拟搜索引擎

    **Lucene:网页抓取与模拟搜索引擎** Lucene是一个开源的全文检索库,由Apache...通过网页抓取、文本处理、索引创建以及搜索功能的实现,我们可以深入理解搜索引擎的核心机制,并且可以根据实际需求进行定制和优化。

    LuceneDemo

    3. 灵活性:Lucene提供了一套完整的API,开发者可以根据需要自定义分词器、评分策略等,实现个性化的全文检索功能。 4. 兼容性:Lucene是用Java编写的,可以运行在任何支持Java的平台上,同时还有其他语言的版本,...

    lucene部分案例的源代码

    Lucene的强大在于其灵活性和可扩展性,可以根据不同项目需求进行定制化开发。通过学习这些案例,开发者可以快速上手,构建出高效、功能丰富的搜索系统。 在实际应用中,结合Lucene与其他技术,如Solr或Elastic...

    基于LUCENE的搜索引擎的设计与实现源代码

    LUCENE提供了丰富的API,开发者可以根据需求扩展其功能,例如自定义Analyzer以适应特定语言的文本处理,或者实现自定义的ScoreFunction以优化排名算法。同时,为了提高性能,可以使用分布式索引、多线程索引和内存...

    lucene源码和程序

    同时,这也可以帮助你定制分析器、优化搜索性能,或者扩展Lucene的功能,例如集成到你的Java应用中,构建自定义的搜索引擎。 总之,Lucene是一个强大的全文检索工具,通过其API,开发者可以轻松地在Java应用中实现...

    全文搜索-Lucene

    3. **评分与排序**:搜索器根据查询对象和索引进行匹配,计算每个匹配文档的相关性分数,如 TF-IDF。 4. **结果返回**:按相关性分数排序,返回最相关的文档列表。 **三、Lucene 的拓展与优化** 1. **多语言支持*...

Global site tag (gtag.js) - Google Analytics