原生的solr中有/get 的request handler实现(org.apache.solr.handler.component.RealTimeGetComponent),实现原理是,先到tlog的内存中去找记录,找不到再到indexSearch中去找。这样当用户利用solrj客户端提交到solr服务端之后,可以不需要等待服务端softcommit,就能立即从服务端中取得最新提交的记录信息。
这样可以避免数据脏写的问题,但是,collection的索引结构使用Nested Document,客户端提交一个Nested Document 记录之后,再使用solrj调用“getById”方法,只能返回parent document了。因为这个原因,在生产环境中,对同一条记录的两次业务操作时间间隔比soft commit的时间周期短,就会产生数据脏写的问题。
要解决这个问题,需要扩展solr的SearchComponent,实现通过Id,可以将文档的子文档(child docuemnt)全部加载。
import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.util.BytesRefBuilder; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.params.SolrParams; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.component.RealTimeGetComponent; import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.BasicResultContext; import org.apache.solr.response.ResultContext; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.transform.DocTransformer; import org.apache.solr.schema.FieldType; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.ReturnFields; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.search.SolrReturnFields; import org.apache.solr.util.RefCounted; public class NestRealtimeGetComponet extends SearchComponent { public static final String COMPONENT_NAME = "nestget"; @Override public void prepare(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrQueryResponse rsp = rb.rsp; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, false)) { return; } // Set field flags ReturnFields returnFields = new SolrReturnFields(rb.req); rb.rsp.setReturnFields(returnFields); } @Override public void process(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrQueryResponse rsp = rb.rsp; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, false)) { return; } String id = params.get("id"); SchemaField idField = req.getSchema().getUniqueKeyField(); FieldType fieldType = idField.getType(); BytesRefBuilder idBytes = new BytesRefBuilder(); fieldType.readableToIndexed(id, idBytes); SolrCore core = req.getCore(); SolrInputDocument doc = RealTimeGetComponent.getInputDocumentFromTlog( core, idBytes.get()); SolrDocumentList docList = new SolrDocumentList(); if (doc != null) { docList.add(convertDocument(doc)); docList.setNumFound(1); } else { RefCounted<SolrIndexSearcher> searchHolder = req.getCore() .getSearcher(); SolrIndexSearcher searcher = searchHolder.get(); // 取得transfer DocTransformer transformer = rsp.getReturnFields().getTransformer(); if (transformer != null) { ResultContext context = new BasicResultContext(null, rsp.getReturnFields(), null, null, req); transformer.setContext(context); } try { int docid = -1; long segAndId = searcher.lookupId(idBytes.get()); if (segAndId >= 0) { int segid = (int) segAndId; LeafReaderContext ctx = searcher.getTopReaderContext() .leaves().get((int) (segAndId >> 32)); docid = segid + ctx.docBase; } if (docid >= 0) { Document luceneDocument = searcher.doc(docid, rsp .getReturnFields().getLuceneFieldNames()); SolrDocument d = toSolrDoc(luceneDocument, core.getLatestSchema()); searcher.decorateDocValueFields(d, docid, searcher.getNonStoredDVs(true)); if (transformer != null) { transformer.transform(d, docid, 0); } docList.add(d); docList.setNumFound(1); } } finally { searchHolder.decref(); } } rb.rsp.addResponse(docList); } private static SolrDocument toSolrDoc(Document doc, IndexSchema schema) { SolrDocument out = new SolrDocument(); for (IndexableField f : doc.getFields()) { // Make sure multivalued fields are represented as lists Object existing = out.get(f.name()); if (existing == null) { SchemaField sf = schema.getFieldOrNull(f.name()); // don't return copyField targets if (sf != null && schema.isCopyFieldTarget(sf)) continue; if (sf != null && sf.multiValued()) { List<Object> vals = new ArrayList<>(); vals.add(f); out.setField(f.name(), vals); } else { out.setField(f.name(), f); } } else { out.addField(f.name(), f); } } return out; } protected SolrDocument convertDocument(SolrInputDocument doc) { SolrDocument sdoc = new SolrDocument(); for (String k : doc.getFieldNames()) { sdoc.setField(k, doc.getFieldValue(k)); } if (doc.hasChildDocuments()) { for (SolrInputDocument s : doc.getChildDocuments()) { sdoc.addChildDocument(convertDocument(s)); } } return sdoc; } }
solrconfig.xml中的配置:
<searchComponent name="nestget" class="com.dfire.tis.solrextend.handler.component.NestRealtimeGetComponet" /> requestHandler name="/select" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <int name="rows">10</int> <str name="df">text</str> </lst> <arr name="last-components"> <str>nestget</str> </arr> </requestHandler>
客户端查询示例:
SolrQuery query = new SolrQuery(); query.setParam("nestget", true); query.set("id", pid); query.setQuery("id:0"); query.setFields("*", "[child parentFilter=type:p childFilter=\"{!terms f=id}" + cid + "\" limit=100]"); QueryResponse r = this.client.query(collection, pid, query); SolrDocumentList doclist = r.getResults(); for (SolrDocument d : doclist) { System.out.println(d.get("id")); System.out.println(); if (d.getChildDocumentCount() > 0) { for (SolrDocument c : d.getChildDocuments()) { StringBuffer f = new StringBuffer(); for (String key : c.getFieldNames()) { f.append(key).append(":").append(c.getFirstValue(key)); } System.out.println(f.toString()); } } }
相关推荐
基于Nested Logit模型的出行路线方式选择和时间价值计算,宗芳,祁文田,本文介绍了Nested Logit模型的效用最大化理论、选择树的建立以及其概率表达式;时间价值的基本计算公式。对人们由长春到吉林的出行路
本文主要探讨了基于Nested Logit模型的电动汽车分时租赁选择行为分析。Nested Logit模型是一种在交通工程和经济学中常用于研究多级选择行为的统计工具,尤其适用于处理具有嵌套结构的数据,如不同的出行方式之间的...
Nested事务是基于JDBC的Savepoint机制实现的,它可以让我们在一个已有的事务内部开启一个新的事务,而这个新事务被称为子事务。当子事务完成时,如果父事务正常提交,那么子事务所做的更改也会被提交;如果父事务...
嵌套阵列DOA估计matlab例程,基于Nested Arrays A Novel Approach to Array Processing With Enhanced Degrees of Freedom。
`react-native-nested-scroll-view`正是为了解决这些问题,它提供了与Android原生`NestedScrollView`类似的功能,使得开发者可以方便地在React Native应用中实现复杂的嵌套滚动布局。 `react-native-nested-scroll-...
"laravel-nested"很可能是一个用于在Laravel中实现嵌套集合(Nested Set)模型的库或者教程。嵌套集合是一种常用的数据结构,特别适合表示具有层级关系的数据,比如目录结构、组织架构等。 在Laravel中,我们通常...
标题和描述均提到了“Weblogic9异常解决nested errors”,这指向了在使用WebLogic Server 9版本时可能遇到的特定错误处理问题。WebLogic Server是Oracle公司提供的一款功能强大的应用服务器,它支持多种标准协议,如...
《深入理解BetterNestedSet:acts_as_nested_set的增强版》 在Ruby on Rails开发中,数据结构的选择对于数据库操作的效率至关重要。其中,Nested Set模型是一种常用的数据组织方式,尤其适用于管理具有层级关系的...
Laravel Nestedset库,如`laravel-nestedset`,是专门为Laravel设计的一个实现嵌套集模型的包。这个包通常由`DaveJamesMiller`维护,它为Laravel提供了处理层级数据的强大工具。 ### 1. 安装与配置 安装`laravel-...
在IT行业中,树形结构是一种常见的数据组织方式,尤其在数据库设计、文件系统、网站导航等领域广泛应用。...结合`nested_category.sql`中的示例,我们可以深入学习如何在实际数据库中实现和操作这种数据结构。
它支持多种高级数据结构,其中就包括嵌套表(Nested Table)。嵌套表是一种特殊类型的集合类型,允许在一个列中存储一组行,这些行可以是同一种类型的数据。本示例“Oracle Nested Table Demo”将向我们展示如何在...
基于粒子群算法(Nested PSO)的电力系统经济调度,matlab平台 solve power system economic dispatch problem by Nested PSO algorithm.
learn_drf_nested_resources 介绍 创建该项目的目的是提供一个完整的示例,该示例说明如何使用在API上实现嵌套资源。 为了使项目尽可能真实,使用处理身份验证。 应用程序 该应用程序公开了一个用于管理博客文章和...
内容概要:本电商系统主要使用ASP.NET技术+BootStrap前端框架+SQLServer数据库,通过对该系统的设计,简化代码实现过程,保留核心功能,可以在实践过程中掌握ASP.NET技术的部分使用方法,如对三层架构开发模式的熟悉...
1、基于springboot+mybatis实现的外卖订餐系统源码+项目说明(毕设).zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为...
在Laravel中,我们通常会使用第三方包,如` Nestedset`,它是一个专门为Laravel设计的实现Nested Set模型的库。该库提供了丰富的函数,如添加、删除、移动节点,以及获取层级关系等,使得在数据库中操作层级数据变得...
Laravel开发-eloquent-nested-attributes 嵌套属性允许您通过父级保存关联记录的属性。默认情况下,嵌套属性更新被关闭,您可以使用$nested属性启用它。启用嵌套属性时,将在模型上定义属性编写器。
一种优化方案是限制递归的深度,或者采用预计算的数据结构(如materialized path或nested set model)来存储评论树,但这需要更复杂的维护逻辑。 总之,基于MyBatis的`collection`标签,结合适当的SQL查询和结果...
这可以通过实现`JsonSerializer`和`JsonDeserializer`接口来实现。例如,我们可以为`Address`类创建自定义序列化器,以便在JSON中添加额外的字段。 4. **GsonBuilder配置** Gson允许通过`GsonBuilder`进行高级配置...