Jetty
jetty启动时注册一个QueuedThreadPool和一些connector和monitor,并初始化一个WebAppContext/ServletContextHandler,同时注册一个LifeCycleListenerLifeCycleListener启动时,注册默认servlet和filter,和扩展的servlet和filter, 并将SolrDispatchFilter注册给WebAppContext/ServletContextHandlerSolrDispatchFilter包含一个solr的CoreContainer容器,该容器管理所有的solr coresSolrDispatchFilter的CoreContainer包含一些管理solr cores的工具,包括寻找core逻辑,注册core的逻辑,管理core的插件,以及处理core的插件(即各种SolrRequestHandler)SolrDispatchFilter的doFilter方法处理请求回应,主要是委托给HttpSolrCall来处理请求回应,HttpSolrCall依据url pattern来寻找对应的SolrRequestHandler来处理请求回应
Solr
core/collection
Schema&Document&Fieldsolr的基本单元信息是document,document是一组描述事物的数据.documents是由字段组成的.字段可以更多的指定模块信息.字段可以包含不同种类的数据,一个name字段可以是text(字符数据), 也可以是一个浮点数,如6或者9.5,所以这个字段的定义比较灵活.但是如果恰当的定义字段,会提高查询效率. 可以通过指定solr的字段类型来告诉字段数据的类型.这个字段类型告诉solr如何解释这个字段,并且如何去查询. 当添加一个document时,solr会从document的字段中拿到数据信息并添加到索引中去.当执行查询时,solr会快速查询索引,返回匹配的文档(document)结果集.
FieldType
字段类型元素fieldType包含4个信息的类型:name,class-实现类的名称,analyzer-用于字段类型的分析,即一些字段属性.
Analyzers&Tokenizer&Filter
字段分析器Analyzers即用于文档索引也用于查询.一个分析器检查字段的文本,并生成一个token流.分析器可能是一个单独的类,也可能是一系列的tokenizer和filter的组合. 分词器把字段数据分解成词汇单元或者tokens,过滤器(filters)检查tokens流,并且保持它们,转换它们,去除它们,或者创建一个新的token.分词器和过滤器可能会结合来形成管道,链条--这一个的输出就是下一个的输入.这样一个分词器和过滤器的序列叫做分析器(analyzer).分析器的结果输出用于匹配查询结果或者是建立索引. 尽管分析处理在索引和查询中都用到.相同的分析处理不必同时用于操作。对于索引,你想要简单化,规范化,词语化.例如,设置所有的字母都小写化,消除标点和重音,提取单词的词干等等.这样做可以增加召回原因.例如 "ram", "Ram" and "RAM"均匹配单词"ram".为了提高查询时间精度,过滤器(filter)可以缩小匹配范围. 分词处理程序输出的tokens定义了那个字段的值或术语,在添加新的文档时可以用于建立索引,或者识别在查询时哪个文档包含这些词(术语).
Field&CopyFiled&DynamicField
字段定义,提供一个名称和字段类型,也可以提供一些选项来覆盖字段类型的选项 复制字段,可以对单个的字段输入信息应用几个不同的字段类型. 动态字段允许solr索引没有在schema.xml中明确定义的字段
data/Index
Directory&Segment
索引目录Directory, 即Lucene中对索引目录的一个抽象lucene的索引目录 StandardDirectoryFactory 根据系统环境选择最佳读写方式 NIOFSDirectory 使用NIO方式读写索引。在windows下这个不是最优,主要原因:在windows下java nio存在bug。 SimpleFSDirectory 简单的磁盘存放,根据上面方法条件判断,在当MMapDirectory无法使用的时候,如果是Windows操作系统,推荐磁盘存储的模式。 此种模式,会有大量的磁盘IO,因此索引的创建和检索严重依赖磁盘性能。 RAMDirectory 这种内存存储方式,它主要用来存放非持久化索引的,也就意味程序关闭,索引就丢失了。 MMapDirectory 内存映射索引模式,一部分放在内存,一部分放在磁盘,但是需要操作系统支持(Swap),最好是64位系统和64位JVM,这样内存才能达到最大的应用。 NRTCachingDirectory (Near Real Time (NRT) Indexing)这是一种内存加磁盘存储的模式,主要用在实时搜索的场景,这在高版本的lucene才有。在solr默认的索引存储目录就是它solr增加的索引目录 HdfsDirectory 把索引存放到hdfs上的,它的使用场景就是索引是海量的。一般不是大数据,不会把数据放到hdfs上。 BlockDirectory 它把索引分成块,在分布式存储的一种概念,一切数据的存储都是block。org.apache.lucene.index.DirectoryReader:负责管理多个索引段org.apache.lucene.index.SegmentReader:负责读取某一个索引段的所有文件org.apache.lucene.index.SegmentInfos:封装了某个索引目录下的所有索引段文件信息,主要跟文件系统打交道org.apache.lucene.index.FieldInfos.FieldInfos:域信息org.apache.lucene.index.TermInfosReader.TermInfosReader:倒排表org.apache.lucene.index.SegmentNorms:主要是加载存储在标准化因子(.nrm)文件
DocValues
在solr4.2以后,引入了一个令人兴奋的功能,一种非常有效的索引方式:DocValue. 这个功能在lucene存在已经一段时间了,但是还没有在solr中使用. 标准的建立索引方式是一中倒排序索引方式,这种方式就是对索引中的所有文档的词语(terms)构造一个列表,挨着term是一个词语(term)所属文档的列表(同样包含词语在一篇文档中出现的次数).这种方式会使搜索速度很快,因为用户通过词语来搜索的,有一个准备好的词语到文档关系的值会使查询处理非常快. 对于其他常见的搜索相关的功能,如排序,分面,高亮.这种方法并不是很有效.这个分面工具,必须查找每篇文档中的每一个词语,然后组成结果集列表,抽取文档的id用来构建分面结果列表.在solr中,这主要是在内存中,并且加载比较慢.(主要依赖于文档数,词数terms等.) 在lucene4.0中,引入了一个新的方法,DocValue字段现在是一个以列为主的字段,具有在索引的时候构建的文档到值(document-to-value)的映射.这个方法保证减轻了一些字段缓存的内存要求,并且是查找分面,排序,分组速度更快.docValues和document的stored=ture存储的值,都是正排索引,单也是有区别的 DocValues是面向列的存储方式,stored=true是面向行的存储方式,如果通过fieldid取列的值可定是用docValues的存储结构更高 Stored=true的存储方式是不会分词的,会将字段原值进行保存,而docValues的保存的值会进行分词DocValues有四种实现方式1. Memory 实现类:org.apache.lucene.codecs.memory.MemoryDocValuesFormat 运行时正排数据会全部加载到内存中,这部分数据在内存中是压缩存储的2. Direct 实现类:org.apache.lucene.codecs.memory.DirectDocValuesFormat 导入到内存中不压缩使用,这个实际使用的效果应该和老版本的fieldcache差不多3. SimpleText 实现类:org.apache.lucene.codecs.simpletext.SimpleTextDocValuesFormat 这个一般不用在环境中使用 以上三种类型定义在lucene-codecs-5.3.0.jar的META-INF/services目录下4. Lucene50(默认使用) 实现类:org.apache.lucene.codecs.lucene50.Lucene50DocValuesFormat Lucene50定义存放在lucene-core-5.3.0.jar的META-INF/services目录下 Lucene50的实现方式和Memory的实现方式大同小异,支持的字段类型更加丰富 在lucene50中将docValues的值分成5种类型: 1. Numeric 2. Binary 3. Sorted 4. SortedSet 5. SortedNumeric 类型是由Schema中的field类型决定的: l StrField或者UUIDField 如果字段不是多值字段,则类型是SORTED 如果是多值字段,则类型是SORTED_SET l 数值字段Trie*或者EnumField 如MultiValue=false,则NUMERIC 如MultiValued=true,则SORTED_SET如果在索引上要进行facet,group,highlight等查询尽量使用docValue
DocIDSet
Document
uniqueKey元素一篇文档的唯一标记 全局的similarity声明可以指定一个自定义的similarity实现,用来让solr处理索引时使用.similarity可以直接通过关联一个无参构造器的类的名称来指定
Schemaless模式
schemaless模式是一组solr功能的集合,允许用户通过简单的索引例子数据快速构建一个有效的schema,而不需要手动的编辑schema.这些solr功能都是在solrconfig.xml中指定的.主要是: schema管理:schema修改是通过Solr API 而不是手动修改来完成的.参考--在solrconfig中管理schema定义. 字段值class的猜测:明显的,不可见的字段运行是通过一组级联的基于值的解析器,这些解析器可以猜测字段值的java类,用来解析Boolean, Integer, Long, Float, Double, 和Date. 基于字段值的java类,自动schema字段添加
RequestHandler
一个request handler就是一个请求处理插件,这个插件定义了在solr处理请求时的请求处理逻辑. solr支持多种request handler.一些用于搜索处理查询,然而其他的用于管理任务,如索引的replication(复制).
SearchHandler&QueryParser$ResponseWriter
搜索查询会被request handler处理,搜索应用选择了一部分request handler作为默认请求处理程序.另外,应用也可以被配置来允许用户重写request handler. 为了处理搜索查询,request handler调用query parser,用于解释查询的条件和参数.不同的查询解析(query parser)支持不同的语法.默认的查询解析器时DisMax解析器.
UpdateHandler
索引处理器属于Request Handlers,用于添加,更新,删除索引中的文档.另外,使用Tika抽取富文档数据,使用Data Import Handler抽取结构化数据.solr自然也就支持 XML, CSV 和 JSON格式的结构化文档. 建立索引的过程:添加内容到solr索引中,如果有需要,修改内容或者删除它.通过添加内容到索引里边,我们使其内容可以搜索. solr索引能够接收不同来源的数据,xml文件,逗号分隔值的(CVS)文件,数据库,普通格式文件如Word或者PDF. 有三种不同的方式来加载数据到索引中: 使用以Apache Tika为基础的Solr Cell框架,用于摄取二进制文件或者结构化文件,比如Office, Word, PDF,和其他所有格式. 通过发送HTTP请求到solr服务器来上传XML文件. 通过solr的java客户端API来写一个自定义的java应用来抽取数据.(如果你正在使用一个应用程序,如内容管理系统,使用java的客户端API也许是一个不错的选择.) 不管抽取数据的方法,有一个普通的带有基本数据结构的数据添加到索引中:一个document包含多个fields,每一个field包含一个name和content,content可能为空.其中一个field被设计为唯一主键ID.
pom.xml
org.apache.solr solr-solrj 6.6.0
solr_server.java + solr_core
public void startEmbeddedSolrJettyServer(){ String tmpSolrHome = "solrcore"; int port = 8985; String context = "/solr"; JettySolrRunner jetty = new JettySolrRunner(tmpSolrHome, context, port); jetty.start(); Thread.sleep(5 * 60 * 1000);} SolrXmlConfig: solr.xml SolrCore: xxxx CoreDescriptor: xxxx/core.properties SolrConfig: xxxx/conf/solrconfig.xml PluginBag: requestHandler IndexSchema: xxxx/conf/schema.xmlor solr_server.java + solr_start + solr_jetty_server_packagepublic void startSolrJettyServer() { System.setProperty("jetty.home", "server/"); System.setProperty("jetty.base", "server/"); System.setProperty("solr.solr.home", "server/solr/"); org.eclipse.jetty.start.Main jetty = new org.eclipse.jetty.start.Main(); String[] args = new String[]{"server/etc/jetty.xml", "server/etc/jetty-http.xml",""}; jetty.init(args); jetty.start(); Thread.sleep(5 * 60 * 1000);}
solr_client.java
public class Solr { public SolrClient getCloudSolrClient() throws MalformedURLException { String zkHost = "192.168.0.112:2181"; CloudSolrClient solrClient = new CloudSolrClient.Builder().withZkHost(zkHost).build(); return solrClient; } public SolrClient getLBHttpSolrClient() throws MalformedURLException { String solrUrls = "http://192.168.0.112:8985/solr,http://192.168.0.112:8986/solr"; LBHttpSolrClient lbclient = new LBHttpSolrClient.Builder().withBaseSolrUrls(solrUrls.split(",")).build(); lbclient.setSoTimeout(5 * 60 * 1000); lbclient.setConnectionTimeout(30 * 1000); return lbclient; } public SolrClient getHttpSolrClient() throws MalformedURLException { String solrUrl = "http://192.168.0.112:8983/solr/images"; HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); return solrClient; } public SolrQuery solrQuery() { SolrQuery query = new SolrQuery();// query.setQuery("*:*"); query.set("fl", "*,score");// query.addFilterQuery("ASOFD: [* TO 1399631920000]"); // query.addFilterQuery("ASOFD:1399631918438"); // query.addFilterQuery("SOURCESECONDARYID:(\"8392342:801\", \"8386910:800\")"); // query.addFilterQuery("SNAPSHOTDATE:20140822"); // query.addFilterQuery("SOURCESYSTEM:MUREXNY"); // query.addFilterQuery("-TRADESTATUS:\"DEAD SRC\""); // query.addFilterQuery("-TRADESTATUS:\"DEAD\""); // query.addFilterQuery("ASOFD:[1408666130000 TO *]"); // query.setParam("fl", "TRADE_URN,SNAPSHOTDATE"); //query.setStart(0); //query.setRows(10); return query; } public Stream
test.java
@Test public void testIndex() throws MalformedURLException{ Solr solr = new Solr(); SolrClient client = solr.getHttpSolrClient(); Mapdoc = new HashMap<>(); doc.put("id", "/home/zhaomeng/Pictures/zm_student.jpg"); doc.put("title", "zm_student"); doc.put("imgurl", "/home/zhaomeng/Pictures/zm_student.jpg"); solr.index(client, solr.toInputDocument(doc)); doc = new HashMap<>(); doc.put("id", "/home/zhaomeng/Pictures/zm_worker1.jpg"); doc.put("title", "worker1"); doc.put("imgurl", "/home/zhaomeng/Pictures/zm_worker1.jpg"); solr.index(client, solr.toInputDocument(doc)); doc = new HashMap<>(); doc.put("id", "/home/zhaomeng/Pictures/zm_worker2.jpg"); doc.put("title", "worker2"); doc.put("imgurl", "/home/zhaomeng/Pictures/zm_worker2.jpg"); solr.index(client, solr.toInputDocument(doc)); } @Test public void testSearch() throws Exception{ Solr solr = new Solr(); SolrClient client = solr.getHttpSolrClient(); SolrQuery query = solr.solrQuery(); query.setRequestHandler("/lireq"); query.add("feature", ImageHelper.extractCEDD("/home/zhaomeng/Pictures/zhaomeng.png")); query.add("field", "ce"); //query.add("extract", "http://192.168.0.112/zhaomeng.png"); query.add("hashes", "12 23"); QueryResponse queryResponse; queryResponse = client.query(query); System.out.println(queryResponse); }
or
http://localhost:10000/solr/lire/update?wt=xml&stream.body=&commit=truehttp://localhost:10000/solr/lire/update?wt=xml&stream.url=http://xxxx/xxx.htmlhttp://localhost:10000/solr/lire/update?wt=xml&stream.body= 5432a &commit=truehttp://localhost:10000/solr/lire/update?wt=xml&stream.body= id:298253 &commit=true *:*