<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.search;

import org.apache.commons.io.FilenameUtils;
import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.QueryValueSource;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.transform.DocTransformer;
import org.apache.solr.response.transform.DocTransformers;
import org.apache.solr.response.transform.RenameFieldTransformer;
import org.apache.solr.response.transform.ScoreAugmenter;
import org.apache.solr.response.transform.TransformerFactory;
import org.apache.solr.response.transform.ValueSourceAugmenter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * The default implementation of return fields parsing for Solr.
 */
public class SolrReturnFields extends ReturnFields {
  // Special Field Keys
  public static final String SCORE = "score";

  private final List<String> globs = new ArrayList<>(1);

  // The lucene field names to request from the SolrIndexSearcher
  // This *may* include fields that will not be in the final response
  private final Set<String> fields = new HashSet<>();

  // Field names that are OK to include in the response.
  // This will include pseudo fields, lucene fields, and matching globs
  private Set<String> okFieldNames = new HashSet<>();

  // The list of explicitly requested fields
  // Order is important for CSVResponseWriter
  private Set<String> reqFieldNames = null;
  
  protected DocTransformer transformer;
  protected boolean _wantsScore = false;
  protected boolean _wantsAllFields = false;

  public SolrReturnFields() {
    _wantsAllFields = true;
  }

  public SolrReturnFields(SolrQueryRequest req) {
    this( req.getParams().getParams(CommonParams.FL), req );
  }

  public SolrReturnFields(String fl, SolrQueryRequest req) {
//    this( (fl==null)?null:SolrPluginUtils.split(fl), req );
    if( fl == null ) {
      parseFieldList((String[])null, req);
    }
    else {
      if( fl.trim().length() == 0 ) {
        // legacy thing to support fl='  ' => fl=*,score!
        // maybe time to drop support for this?
        // See ConvertedLegacyTest
        _wantsScore = true;
        _wantsAllFields = true;
        transformer = new ScoreAugmenter(SCORE);
      }
      else {
        parseFieldList( new String[]{fl}, req);
      }
    }
  }

  public SolrReturnFields(String[] fl, SolrQueryRequest req) {
    parseFieldList(fl, req);
  }

  private void parseFieldList(String[] fl, SolrQueryRequest req) {
    _wantsScore = false;
    _wantsAllFields = false;
    if (fl == null || fl.length == 0 || fl.length == 1 && fl[0].length()==0) {
      _wantsAllFields = true;
      return;
    }

    NamedList<String> rename = new NamedList<>();
    DocTransformers augmenters = new DocTransformers();
    for (String fieldList : fl) {
      add(fieldList,rename,augmenters,req);
    }
    for( int i=0; i<rename.size(); i++ ) {
      String from = rename.getName(i);
      String to = rename.getVal(i);
      okFieldNames.add( to );
      boolean copy = (reqFieldNames!=null && reqFieldNames.contains(from));
      if(!copy) {
        // Check that subsequent copy/rename requests have the field they need to copy
        for(int j=i+1; j<rename.size(); j++) {
          if(from.equals(rename.getName(j))) {
            rename.setName(j, to); // copy from the current target
            if(reqFieldNames==null) {
              reqFieldNames = new LinkedHashSet<>();
            }
            reqFieldNames.add(to); // don't rename our current target
          }
        }
      }
      augmenters.addTransformer( new RenameFieldTransformer( from, to, copy ) );
    }

    if( augmenters.size() == 1 ) {<commit_msg>SOLR-8902: fix glob test (put back the fields.clear())<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.search;

import org.apache.commons.io.FilenameUtils;
import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.QueryValueSource;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.transform.DocTransformer;
import org.apache.solr.response.transform.DocTransformers;
import org.apache.solr.response.transform.RenameFieldTransformer;
import org.apache.solr.response.transform.ScoreAugmenter;
import org.apache.solr.response.transform.TransformerFactory;
import org.apache.solr.response.transform.ValueSourceAugmenter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * The default implementation of return fields parsing for Solr.
 */
public class SolrReturnFields extends ReturnFields {
  // Special Field Keys
  public static final String SCORE = "score";

  private final List<String> globs = new ArrayList<>(1);

  // The lucene field names to request from the SolrIndexSearcher
  // This *may* include fields that will not be in the final response
  private final Set<String> fields = new HashSet<>();

  // Field names that are OK to include in the response.
  // This will include pseudo fields, lucene fields, and matching globs
  private Set<String> okFieldNames = new HashSet<>();

  // The list of explicitly requested fields
  // Order is important for CSVResponseWriter
  private Set<String> reqFieldNames = null;
  
  protected DocTransformer transformer;
  protected boolean _wantsScore = false;
  protected boolean _wantsAllFields = false;

  public SolrReturnFields() {
    _wantsAllFields = true;
  }

  public SolrReturnFields(SolrQueryRequest req) {
    this( req.getParams().getParams(CommonParams.FL), req );
  }

  public SolrReturnFields(String fl, SolrQueryRequest req) {
//    this( (fl==null)?null:SolrPluginUtils.split(fl), req );
    if( fl == null ) {
      parseFieldList((String[])null, req);
    }
    else {
      if( fl.trim().length() == 0 ) {
        // legacy thing to support fl='  ' => fl=*,score!
        // maybe time to drop support for this?
        // See ConvertedLegacyTest
        _wantsScore = true;
        _wantsAllFields = true;
        transformer = new ScoreAugmenter(SCORE);
      }
      else {
        parseFieldList( new String[]{fl}, req);
      }
    }
  }

  public SolrReturnFields(String[] fl, SolrQueryRequest req) {
    parseFieldList(fl, req);
  }

  private void parseFieldList(String[] fl, SolrQueryRequest req) {
    _wantsScore = false;
    _wantsAllFields = false;
    if (fl == null || fl.length == 0 || fl.length == 1 && fl[0].length()==0) {
      _wantsAllFields = true;
      return;
    }

    NamedList<String> rename = new NamedList<>();
    DocTransformers augmenters = new DocTransformers();
    for (String fieldList : fl) {
      add(fieldList,rename,augmenters,req);
    }
    for( int i=0; i<rename.size(); i++ ) {
      String from = rename.getName(i);
      String to = rename.getVal(i);
      okFieldNames.add( to );
      boolean copy = (reqFieldNames!=null && reqFieldNames.contains(from));
      if(!copy) {
        // Check that subsequent copy/rename requests have the field they need to copy
        for(int j=i+1; j<rename.size(); j++) {
          if(from.equals(rename.getName(j))) {
            rename.setName(j, to); // copy from the current target
            if(reqFieldNames==null) {
              reqFieldNames = new LinkedHashSet<>();
            }
            reqFieldNames.add(to); // don't rename our current target
          }
        }
      }
      augmenters.addTransformer( new RenameFieldTransformer( from, to, copy ) );
    }
    if( !_wantsAllFields && !globs.isEmpty() ) {
      // TODO??? need to fill up the fields with matching field names in the index
      // and add them to okFieldNames?
      // maybe just get all fields?
      // this would disable field selection optimization... i think thatis OK
      fields.clear(); // this will get all fields, and use wantsField to limit
    }

    if( augmenters.size() == 1 ) {
{'fraction_non_alphanumeric': 0.10472160784690836, 'fraction_numerical': 0.0028848927781517453, 'mean_word_length': 3.421768707482993, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2369049', 'n_tokens_mistral': 3035, 'n_tokens_neox': 2974, 'n_words': 903}