`

solr中如何定义自己的解析器插件(QParserPlugin)

 
阅读更多
/*****************************************************/  
>solr中如何定义自己的解析器插件
/*****************************************************/  

0.为什么要自定义自己的解析器插件
/*****************************************************/
// 因为solr默认的LuceneQParserPlugin解析器插件是不支持很多高级查询的如
// SpanQuery,MoreLikeThis等,如果要使用这些特性就必须自定的解析器插件。
/*****************************************************/



1.显示自定义解析器插件的方法
/*****************************************************/
//定义的插件必须继承自org.apache.solr.search.QParserPlugin;
public class MyParserPlugin extends QParserPlugin {
	@Override
	public void init(NamedList args) {
	}

	@Override
	public QParser createParser(String qstr, SolrParams localParams,
			SolrParams params, SolrQueryRequest req) {
		//创建出内部类就可以了
		//return new MyParserPlugin.MyParser(qstr, localParams, params, req);
	}
	
	//继承自org.apache.solr.search.Qparser;
	private class MyParser extends QParser{
		public MyParser(String qstr, SolrParams localParams, SolrParams params,
				SolrQueryRequest req) {
			super(qstr, localParams, params, req);
		}
		@Override
		public Query parse() throws ParseException {
			//返回org.apache.lucene.search.Query;就可以了其他的不用管
			return null;
		}
	}
}

//如何配置自定义的解析器插件
// <queryParser name="simple" class="com.zyb.javacc.QParserPlugin" /> \
// 然后在查询的时候需要指定defType这个属性进行指定是哪个解析器来解析你的检索式
// 如:http://localhost:8080/testSolr/select/q=*:*&defType=simple;
// 或者也可以在指定的查询处理器中默认的指定也是可以的
//<requestHandler name="search" class="solr.SearchHandler" default="true">
// <lst name="defaults">
//   <str name="defType">simple</str>  //通过在这里指定后就不用在Url后面显示的指定
//   <str name="echoParams">explicit</str>
//   <int name="rows">10</int>
// </lst>
//</requestHandler> 
/*****************************************************/  



2.原理说明
/*****************************************************/  
public abstract class QParserPlugin implements NamedListInitializedPlugin {
  /** internal use - name of the default parser */
  public static String DEFAULT_QTYPE = LuceneQParserPlugin.NAME;//solr默认的解析器插件

  /** internal use - name to class mappings of builtin parsers */
  //solr中存在的查询解析器插件
  public static final Object[] standardPlugins = {
   // LuceneQParserPlugin.NAME, LuceneQParserPlugin.class,
    OldLuceneQParserPlugin.NAME, OldLuceneQParserPlugin.class,
    FunctionQParserPlugin.NAME, FunctionQParserPlugin.class,
    PrefixQParserPlugin.NAME, PrefixQParserPlugin.class,
    BoostQParserPlugin.NAME, BoostQParserPlugin.class,
    DisMaxQParserPlugin.NAME, DisMaxQParserPlugin.class,
    ExtendedDismaxQParserPlugin.NAME, ExtendedDismaxQParserPlugin.class,
    FieldQParserPlugin.NAME, FieldQParserPlugin.class,
    RawQParserPlugin.NAME, RawQParserPlugin.class,
    TermQParserPlugin.NAME, TermQParserPlugin.class,
    NestedQParserPlugin.NAME, NestedQParserPlugin.class,
    FunctionRangeQParserPlugin.NAME, FunctionRangeQParserPlugin.class,
    SpatialFilterQParserPlugin.NAME, SpatialFilterQParserPlugin.class,
    SpatialBoxQParserPlugin.NAME, SpatialBoxQParserPlugin.class,
  };

  /** return a {@link QParser} */
  public abstract QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req);



//采用lucene解析器的实现
public class LuceneQParserPlugin extends QParserPlugin {
  public static String NAME = "lucene";

  public void init(NamedList args) {
  }

  @Override
  public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
   // return new LuceneQParser(qstr, localParams, params, req);
  }
}

//继承自QParser会带来很多好处因为他已经帮我们实现了部分我们不需要实现的东西我们只需要关心怎么去生成
//org.apache.lucene.search.Query这个接口的实现类就可以了
//QParser是一个抽象类他可以通过this.qstr得到检索式如*:*等
class LuceneQParser extends QParser {
  String sortStr;
  // SolrQueryParser lparser;//SolrQueryParser还是继承自org.apache.lucene.queryParser;所以还是采用的lucene
			  //的原有解析器他是不能够满足做spanQuery,moreLikeThis这样的查询的
			  //除非自己写扩展的查询解析器插件才可以实现

  public LuceneQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
    super(qstr, localParams, params, req);
  }

  //查询解析器的目的就是为了返回一个org.apache.lucene.search.Query的实现类就可以了
  //那么这就是和solr无关的东西了只要构造了Query的实现类的对象就可以顺利的做任何类型的查询
  @Override
  public Query parse() throws ParseException {
    String qstr = getString();

    String defaultField = getParam(CommonParams.DF);
    if (defaultField==null) {
      defaultField = getReq().getSchema().getDefaultSearchFieldName();
    }
    lparser = new SolrQueryParser(this, defaultField);

    // these could either be checked & set here, or in the SolrQueryParser constructor
    String opParam = getParam(QueryParsing.OP);
    if (opParam != null) {
      lparser.setDefaultOperator("AND".equals(opParam) ? QueryParser.Operator.AND : QueryParser.Operator.OR);
    } else {
      // try to get default operator from schema
      QueryParser.Operator operator = getReq().getSchema().getSolrQueryParser(null).getDefaultOperator();
      lparser.setDefaultOperator(null == operator ? QueryParser.Operator.OR : operator);
    }

    return lparser.parse(qstr);
  }


  @Override
  public String[] getDefaultHighlightFields() {
    return new String[]{lparser.getField()};
  }
  
}


//这里继承好像没什么用处
class OldLuceneQParser extends LuceneQParser {
  String sortStr;

  public OldLuceneQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
    super(qstr, localParams, params, req);
  }

  @Override
  public Query parse() throws ParseException {
    // handle legacy "query;sort" syntax
    if (getLocalParams() == null) {
      String qstr = getString();
      sortStr = getParams().get(CommonParams.SORT);
      if (sortStr == null) {
        // sort may be legacy form, included in the query string
        List<String> commands = StrUtils.splitSmart(qstr,';');
        if (commands.size() == 2) {
          qstr = commands.get(0);
          sortStr = commands.get(1);
        } else if (commands.size() == 1) {
          // This is need to support the case where someone sends: "q=query;"
          qstr = commands.get(0);
        }
        else if (commands.size() > 2) {
          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "If you want to use multiple ';' in the query, use the 'sort' param.");
        }
      }
      setString(qstr);
    }

    return super.parse();
  }

  @Override
  public SortSpec getSort(boolean useGlobal) throws ParseException {
    SortSpec sort = super.getSort(useGlobal);
    if (sortStr != null && sortStr.length()>0 && sort.getSort()==null) {
      Sort oldSort = QueryParsing.parseSort(sortStr, getReq());
      if( oldSort != null ) {
        sort.sort = oldSort;
      }
    }
    return sort;
  }

}
}
/*****************************************************/  


3.solr查询内部实现
/*****************************************************/  
  org.apache.solr.handler.component.searchHandler.@Override
  public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception, ParseException, InstantiationException, IllegalAccessException
  {
    // int sleep = req.getParams().getInt("sleep",0);
    // if (sleep > 0) {log.error("SLEEPING for " + sleep);  Thread.sleep(sleep);}
    //ResponseBuilder rb = new ResponseBuilder();//在查询的时候最重要的对象
    rb.req = req;
    rb.rsp = rsp;
    rb.components = components;
    rb.setDebug(req.getParams().getBool(CommonParams.DEBUG_QUERY, false));

    final RTimer timer = rb.isDebug() ? new RTimer() : null;

    if (timer == null) {
      // non-debugging prepare phase
      //for( SearchComponent c : components ) {
       // c.prepare(rb);//准备查询组件
      //}
    } else {
      // debugging prepare phase
      RTimer subt = timer.sub( "prepare" );
     // for( SearchComponent c : components ) {
      //  rb.setTimer( subt.sub( c.getName() ) );
        //c.prepare(rb);
      //  rb.getTimer().stop();
     // }
      subt.stop();
    }

    if (rb.shards == null) {
      // a normal non-distributed request

      // The semantics of debugging vs not debugging are different enough that
      // it makes sense to have two control loops
      if(!rb.isDebug()) {
        // Process 根据组件处理查询请求
        //for( SearchComponent c : components ) {
         // c.process(rb);
       // }
      }
      else {
        // Process
        RTimer subt = timer.sub( "process" );
        //for( SearchComponent c : components ) {
        //  rb.setTimer( subt.sub( c.getName() ) );
        //  c.process(rb);
        //  rb.getTimer().stop();
        //}
        subt.stop();
        timer.stop();

        // add the timing info
        if( rb.getDebugInfo() == null ) {
          rb.setDebugInfo( new SimpleOrderedMap<Object>() );
        }
        rb.getDebugInfo().add( "timing", timer.asNamedList() );
      }

    } else {
      // a distributed request

      HttpCommComponent comm = new HttpCommComponent();

      if (rb.outgoing == null) {
        rb.outgoing = new LinkedList<ShardRequest>();
      }
      rb.finished = new ArrayList<ShardRequest>();

      int nextStage = 0;
      do {
        rb.stage = nextStage;
        nextStage = ResponseBuilder.STAGE_DONE;

        // call all components
        for( SearchComponent c : components ) {
          // the next stage is the minimum of what all components report
          nextStage = Math.min(nextStage, c.distributedProcess(rb));
        }


        // check the outgoing queue and send requests
        while (rb.outgoing.size() > 0) {

          // submit all current request tasks at once
          while (rb.outgoing.size() > 0) {
            ShardRequest sreq = rb.outgoing.remove(0);
            sreq.actualShards = sreq.shards;
            if (sreq.actualShards==ShardRequest.ALL_SHARDS) {
              sreq.actualShards = rb.shards;
            }
            sreq.responses = new ArrayList<ShardResponse>();

            // TODO: map from shard to address[]
            for (String shard : sreq.actualShards) {
              ModifiableSolrParams params = new ModifiableSolrParams(sreq.params);
              params.remove(ShardParams.SHARDS);      // not a top-level request
              params.remove("indent");
              params.remove(CommonParams.HEADER_ECHO_PARAMS);
              params.set(ShardParams.IS_SHARD, true);  // a sub (shard) request
              String shardHandler = req.getParams().get(ShardParams.SHARDS_QT);
              if (shardHandler == null) {
                params.remove(CommonParams.QT);
              } else {
                params.set(CommonParams.QT, shardHandler);
              }
              comm.submit(sreq, shard, params);
            }
          }


          // now wait for replies, but if anyone puts more requests on
          // the outgoing queue, send them out immediately (by exiting
          // this loop)
          while (rb.outgoing.size() == 0) {
            ShardResponse srsp = comm.takeCompletedOrError();
            if (srsp == null) break;  // no more requests to wait for

            // Was there an exception?  If so, abort everything and
            // rethrow
            if (srsp.getException() != null) {
              comm.cancelAll();
              if (srsp.getException() instanceof SolrException) {
                throw (SolrException)srsp.getException();
              } else {
                throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, srsp.getException());
              }
            }

            rb.finished.add(srsp.getShardRequest());

            // let the components see the responses to the request
            for(SearchComponent c : components) {
              c.handleResponses(rb, srsp.getShardRequest());
            }
          }
        }

        for(SearchComponent c : components) {
            c.finishStage(rb);
         }

        // we are done when the next stage is MAX_VALUE
      } while (nextStage != Integer.MAX_VALUE);
    }
  }




org.apache.solr.handler.component.QueryComponent.public void prepare(ResponseBuilder rb) throws IOException
  {
    //ResponseBuilder在查询的时候是在关键的对象
    SolrQueryRequest req = rb.req;
    //现在的参数样子
    //{params(indent=on&start=0&q=*:*&version=2.2&rows=10),
    // defaults(echoParams=explicit&rows=10&defType=simple)}
    // defaults表示在requestHandler节点中定义的默认参数

    SolrParams params = req.getParams();
    if (!params.getBool(COMPONENT_NAME, true)) {
      return;
    }
    SolrQueryResponse rsp = rb.rsp;

    // Set field flags
    String fl = params.get(CommonParams.FL);
    int fieldFlags = 0;
    if (fl != null) {
      fieldFlags |= SolrPluginUtils.setReturnFields(fl, rsp);
    }
    rb.setFieldFlags( fieldFlags );

    //String defType = params.get(QueryParsing.DEFTYPE,QParserPlugin.DEFAULT_QTYPE);

    if (rb.getQueryString() == null) {
      rb.setQueryString( params.get( CommonParams.Q ) );
    }

    try {
      //根据defType得到自定的解析插件对象
      //QParser parser = QParser.getParser(rb.getQueryString(), defType, req);
      //rb.setQuery( parser.getQuery() );//通过getQuery()然后调用parse(str)
      //返回生成查询对象,关键在于怎么写
      //rb.setSortSpec( parser.getSort(true) );
      //rb.setQparser(parser);

      String[] fqs = req.getParams().getParams(CommonParams.FQ);
      if (fqs!=null && fqs.length!=0) {
        List<Query> filters = rb.getFilters();
        if (filters==null) {
          filters = new ArrayList<Query>(fqs.length);
        }
        for (String fq : fqs) {
          if (fq != null && fq.trim().length()!=0) {
            QParser fqp = QParser.getParser(fq, null, req);
            filters.add(fqp.getQuery());
          }
        }
        // only set the filters if they are not empty otherwise
        // fq=&someotherParam= will trigger all docs filter for every request 
        // if filter cache is disabled
        if (!filters.isEmpty()) {
          rb.setFilters( filters );
        }
      }
    } catch (ParseException e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
    }

    // TODO: temporary... this should go in a different component.
    //如果有分布式查询就得到shards参数通过,进行切割
    //String shards = params.get(ShardParams.SHARDS);
    //if (shards != null) {
     // List<String> lst = StrUtils.splitSmart(shards, ",", true);
     // rb.shards = lst.toArray(new String[lst.size()]);
    //}
    //String shards_rows = params.get(ShardParams.SHARDS_ROWS);
    //if(shards_rows != null) {
      //rb.shards_rows = Integer.parseInt(shards_rows);
    //}
    //String shards_start = params.get(ShardParams.SHARDS_START);
    //if(shards_start != null) {
      //rb.shards_start = Integer.parseInt(shards_start);
    //}

    boolean grouping = params.getBool(GroupParams.GROUP, false);
    if (!grouping) {
      return;
    }
    SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand();
    SolrIndexSearcher searcher = rb.req.getSearcher();
    GroupingSpecification groupingSpec = new GroupingSpecification();
    rb.setGroupingSpec(groupingSpec);

    //TODO: move weighting of sort
    Sort groupSort = searcher.weightSort(cmd.getSort());
    // groupSort defaults to sort
    String groupSortStr = params.get(GroupParams.GROUP_SORT);
    if (groupSort == null) {
      groupSort = new Sort();
    }
    //TODO: move weighting of sort
    Sort sortWithinGroup = groupSortStr == null ?  groupSort : searcher.weightSort(QueryParsing.parseSort(groupSortStr, req));
    groupingSpec.setSortWithinGroup(sortWithinGroup);
    groupingSpec.setGroupSort(groupSort);

    String formatStr = params.get(GroupParams.GROUP_FORMAT, Grouping.Format.grouped.name());
    Grouping.Format responseFormat;
    try {
       responseFormat = Grouping.Format.valueOf(formatStr);
    } catch (IllegalArgumentException e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, String.format("Illegal %s parameter", GroupParams.GROUP_FORMAT));
    }
    groupingSpec.setResponseFormat(responseFormat);

    groupingSpec.setFields(params.getParams(GroupParams.GROUP_FIELD));
    groupingSpec.setQueries(params.getParams(GroupParams.GROUP_QUERY));
    groupingSpec.setGroupOffset(params.getInt(GroupParams.GROUP_OFFSET, 0));
    groupingSpec.setGroupLimit(params.getInt(GroupParams.GROUP_LIMIT, 1));
    groupingSpec.setOffset(rb.getSortSpec().getOffset());
    groupingSpec.setLimit(rb.getSortSpec().getCount());
    groupingSpec.setIncludeGroupCount(params.getBool(GroupParams.GROUP_TOTAL_COUNT, false));
    groupingSpec.setMain(params.getBool(GroupParams.GROUP_MAIN, false));
    groupingSpec.setNeedScore((cmd.getFlags() & SolrIndexSearcher.GET_SCORES) != 0);
    groupingSpec.setTruncateGroups(params.getBool(GroupParams.GROUP_TRUNCATE, false));
  }
/*****************************************************/  

 

分享到:
评论

相关推荐

    solr中文解析器以及使用文档

    3. **配置Solr的中文解析器**:在Solr中使用IK Analyzer,需要在solrconfig.xml和schema.xml这两个配置文件中进行设置。首先,需要在solrconfig.xml中指定查询分析器和索引分析器为IK Analyzer;然后,在schema.xml...

    solr配置中文解析器和将数据导入solr索引库时所需的jar包

    本篇文章将深入探讨如何在Solr中配置中文解析器以及在导入数据到Solr索引库时所需关注的jar包。 首先,让我们来了解Solr中的中文解析器。在Solr中,解析器是处理文本输入的关键组件,它负责将原始文本转化为可搜索...

    solr(中文分词器)集群

    每个SolrCore需要定义自己的索引结构,这可以通过创建一个名为`solrconfig.xml`的配置文件来完成。此外,还需要为每个SolrCore指定一个独一无二的名字,并在`solr.xml`中注册到Zookeeper。这样,Solr就能知道集群中...

    solr中文分词器

    Solr中文分词器是Apache Solr搜索引擎系统中用于处理中文文本的核心组件,它使得Solr能够对中文文档进行有效的索引和搜索。在Solr中,分词器(Tokenizer)是分析器(Analyzer)的一部分,负责将输入的文本拆分成可被...

    solr实现电商自定义打分

    这通常涉及到修改`schema.xml`或`managed-schema`文件,定义新的查询字段类型和查询解析器。例如,可以创建一个新的查询解析器,专门为自定义打分设计。 此外,Solr还支持插件开发,可以编写自定义的`Similarity`类...

    Solr5.4中文分词

    在Solr 5.4版本中,对中文分词的支持是通过特定的分词器实现的。本文将详细介绍如何在Solr 5.4中配置中文分词库。 首先,"Solr5.4中文分词"这个标题表明我们关注的是针对Solr 5.4的一个特定分词解决方案。这通常...

    solr7.5_ik分词器,suggest配置源文件文件

    2. 配置schema.xml:在Solr的配置文件中,需要定义字段类型(fieldType)来使用Ik分词器。例如,可以创建一个名为`text_ik`的字段类型,指定其分析器为`org.wltea.analyzer.lucene.IKAnalyzer`。 3. 配置分析器:在...

    solr 5.x 和 6.x 最新中文分词器

    通常在`schema.xml`或`managed-schema`中定义字段类型(FieldType),并设置对应的分词器。例如,使用IK Analyzer: ```xml &lt;fieldType name="text_ik" class="solr.TextField"&gt; ``` 这里,`...

    solr中文分词器ik-analyzer-solr7.x

    在Solr中,分词器是核心组件之一,负责对输入的中文文本进行分词处理,生成可以被索引和查询的关键词。IK Analyzer作为Solr的插件,可以实现以下功能: 1. **中文分词**:通过内置的中文词典,将输入的中文句子拆分...

    Solr-Plugins:Solr 的各种插件

    以上只是Solr插件系统的冰山一角,实际应用中可能涉及到更多定制化的插件,如地理位置搜索插件、流式处理插件等。通过熟练掌握和利用这些插件,开发者可以打造出满足特定业务需求的高效、智能的搜索引擎解决方案。在...

    solr ik分词器

    本教程将详细解释如何在Solr中安装和使用IK分词器。 首先,让我们理解一下什么是分词器。在文本检索和自然语言处理领域,分词是将连续的文本分解成有意义的词语单元(如单词或短语)的过程。对于中文,由于没有明显...

    支持 Solr7 的 ik 分词器

    2. **Solr7.0集成IK分词器.docx**:这是一份详细的文档,指导用户如何在 Solr 7 中配置和使用 ik 分词器。它会涵盖安装步骤、配置参数设置以及可能出现的问题及其解决方案,对于初次使用者来说非常有价值。 3. **ik...

    支持solr5.5 solr6.0中IK分词需要的资料

    3. **配置分析器**:在Solr的`schema.xml`或`managed-schema`文件中,为需要使用IK分词器的字段定义分析器。 ```xml &lt;fieldType name="text_ik" class="solr.TextField" positionIncrementGap="100"&gt; ...

    match-query-parser,在solr中使用不同的查询时间分析器搜索单个字段.zip

    在Solr中,查询分析器的作用是在查询执行前解析和处理用户输入的查询字符串。默认情况下,Solr使用标准查询分析器(Standard Query Parser),但有时我们可能需要针对特定字段定制查询行为,例如,处理特殊查询语法...

    solr7.3.1中文分词器

    描述中提到的"solr7.3.1种需要的中文IK分词器",IK(Intelligent Chinese Analyzer)分词器是一个强大的、成熟的中文分词组件,广泛应用于各种Java开发的搜索系统中。IK分词器支持多种分词模式,包括精确模式、全...

    solr搜索插件

    6. **扩展性与定制化**:Solr允许通过插件机制进行扩展,比如自定义查询解析器、过滤器、排序策略等,以满足特定的业务需求。此外,Solr还可以集群部署,实现分布式搜索和高可用性。 在实际应用中,Solr搜索插件...

    针对Solr6.6.0的IK分词器

    Solr6.6.0中的IK分词器是用于对中文文本进行精细化分词的工具,它是基于Apache Lucene的开源搜索引擎项目Solr的一个插件。这个插件的主要任务是将中文句子分解成一系列有意义的词语,以便于索引和搜索。在Solr中,...

    solr6.6.0源码

    Solr 6.6.0 提供了丰富的插件机制,允许开发者自定义请求处理器、查询解析器、过滤器等,满足个性化需求。 七、安全与权限控制 Solr支持基本的身份验证和授权机制,通过`security.json`配置文件可以实现对用户和...

Global site tag (gtag.js) - Google Analytics