1

我正在使用带有 Schemaless Solr 的 Spring Data Solr。有些点我无法连接:何时以及如何创建架构字段?

以下页面说明

每当刷新应用程序上下文并根据属性配置将新字段填充到索引中时,自动模式填充将检查您的域类型。这需要 solr 以无模式模式运行。

使用 @Indexed 提供额外的细节,比如要使用的特定 solr 类型。

它还显示一个 curl 请求:

// curl ../solr/collection1/schema/fields -X POST -H 'Content-type:application/json'

但是,当我运行一个使用 @Indexed 注释的字段的简单示例时,我看不到 SOLR 上调用 /schema/fields API。这些字段是如何创建的?

我问的原因是它们似乎是使用 multiValued=true 自动创建的。我没有看到 @Indexed 注释将 multiValued 作为参数。如何在创建字段时强制 Spring Data Solr 将字段声明为非多值?

现在,所有这一切都是为了解决我看到的这个异常。

java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.util.Assert.notNull(Assert.java:126)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:426)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readCollection(MappingSolrConverter.java:601)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:440)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:412)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.getPropertyValue(MappingSolrConverter.java:395)
at org.springframework.data.solr.core.convert.MappingSolrConverter.getValue(MappingSolrConverter.java:206)
at org.springframework.data.solr.core.convert.MappingSolrConverter$1.doWithPersistentProperty(MappingSolrConverter.java:194)
at org.springframework.data.solr.core.convert.MappingSolrConverter$1.doWithPersistentProperty(MappingSolrConverter.java:186)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:309)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:186)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:174)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:149)
at org.springframework.data.solr.core.SolrTemplate.convertSolrDocumentListToBeans(SolrTemplate.java:560)
at org.springframework.data.solr.core.SolrTemplate.convertQueryResponseToBeans(SolrTemplate.java:552)
at org.springframework.data.solr.core.SolrTemplate.createSolrResultPage(SolrTemplate.java:369)
at org.springframework.data.solr.core.SolrTemplate.doQueryForPage(SolrTemplate.java:300)
at org.springframework.data.solr.core.SolrTemplate.queryForPage(SolrTemplate.java:308)
at org.springframework.data.solr.repository.support.SimpleSolrRepository.findAll(SimpleSolrRepository.java:111)
at org.springframework.data.solr.repository.support.SimpleSolrRepository.findAll(SimpleSolrRepository.java:106)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at 

我的猜测是发生异常是因为值作为集合返回?

我试图通过代码来了解发生了什么。导致问题的字段是“名称”,值为 [product-1]。尝试将 solr 文档解组为 POJO 时发生异常。

首先我们进入下面的方法:

    private <T> T readValue(Object value, TypeInformation<?> type, Object parent) {
        if (value == null) {
            return null;
        }

        Assert.notNull(type);
        Class<?> rawType = type.getType();
        if (hasCustomReadTarget(value.getClass(), rawType)) {
            return (T) convert(value, rawType);
        }

        Object documentValue = null;
        if (value instanceof SolrInputField) {
            documentValue = ((SolrInputField) value).getValue();
        } else {
            documentValue = value;
        }

        if (documentValue instanceof Collection) {
            return (T) readCollection((Collection<?>) documentValue, type, parent);
        } else if (canConvert(documentValue.getClass(), rawType)) {
            return (T) convert(documentValue, rawType);
        }

        return (T) documentValue;

    }

调用该方法时,值为集合,类型为java.lang.String。这会导致 if(documentValue instanceof Collection) 被选中,从而导致执行以下方法:

        private Object readCollection(Collection<?> source, TypeInformation<?> type, Object parent) {
        Assert.notNull(type);

        Class<?> collectionType = type.getType();
        if (CollectionUtils.isEmpty(source)) {
            return source;
        }

        collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;

        Collection<Object> items;
        if (type.getType().isArray()) {
            items = new ArrayList<Object>();
        } else {
            items = CollectionFactory.createCollection(collectionType, source.size());
        }

        TypeInformation<?> componentType = type.getComponentType();

        Iterator<?> it = source.iterator();
        while (it.hasNext()) {
            items.add(readValue(it.next(), componentType, parent));
        }

        return type.getType().isArray() ? convertItemsToArrayOfType(type, items) : items;
    }

在这个方法中,我们最终调用 type.getComponentType(),它返回 null 并最终导致 Assert.notNull() 失败。

我在这一切中缺少什么?

我的代码如下。启动和配置类:

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableSolrRepositories(schemaCreationSupport=true, basePackages = { "com.example.solrdata" }, multicoreSupport = true)
public class Application {

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}
}

型号类:

@SolrDocument(solrCoreName = "collection1")
public class Product {

@Id
String id;
@Indexed
String name;

public Product(String id, String name) {
    this.id = id;
    this.name = name;
}

public Product() {
    super();
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}}

存储库:

public interface ProductRepository extends SolrCrudRepository<Product, String> {}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class SolrProductRepositoryTest  {

@Autowired
private ProductRepository repo;

@Before @After
public void setup(){
    repo.deleteAll();
}

@Test
public void testCRUD() {
    assertEquals(0, repo.count());
    Product product = new Product("1","product-1");
    repo.save(product);
    assertEquals(1, repo.count());
    Product product2 = repo.findOne(product.getId());
    assertEquals(product2.getName(), product.getName());
}}

最后,我的 POM:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.3.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-solr</artifactId>
    </dependency>
</dependencies>
4

1 回答 1

0

当使用具有默认值的 Solr 4.10 时,不幸的是JSONResponseWriterinsolrconfig.xml用作text/pain内容类型。

<queryResponseWriter name="json" class="solr.JSONResponseWriter">
  <str name="content-type">text/plain; charset=UTF-8</str>
</queryResponseWriter>

这会导致内容类型协商SolrSchemaRequest以静默方式失败并跳过模式更新步骤 - 并且 solr 默认字段类型猜测在该位置开始。

设置content-typeapplication/json允许根据 bean 定义添加字段。

@SolrDocument(solrCoreName = "collection1")
public static class SomeDomainType {

    @Indexed @Id 
    String id;

    @Indexed 
    String indexedStringWithoutType;

    @Indexed(name = "namedField", type = "string", searchable = false) 
    String justAStoredField;

    @Indexed 
    List<String> listField;

    @Indexed(type = "tdouble") 
    Double someDoubleValue;
}

{
    responseHeader: {
        status: 0,
        QTime: 86
    },
    fields: [
        {
            name: "_version_",
            type: "long",
            indexed: true,
            stored: true
        },
        {
            name: "id",
            type: "string",
            multiValued: false,
            indexed: true,
            required: true,
            stored: true,
            uniqueKey: true
        }
    ]
}

架构更新后

{
    responseHeader: {
        status: 0,
        QTime: 1
    },
    fields: [
        {
            name: "_version_",
            type: "long",
            indexed: true,
            stored: true
        },
        {
            name: "id",
            type: "string",
            multiValued: false,
            indexed: true,
            required: true,
            stored: true,
            uniqueKey: true
        },
        {
            name: "indexedStringWithoutType",
            type: "string",
            multiValued: false,
            indexed: true,
            required: false,
            stored: true
        },
        {
            name: "listField",
            type: "string",
            multiValued: true,
            indexed: true,
            required: false,
            stored: true
        },
        {
            name: "namedField",
            type: "string",
            multiValued: false,
            indexed: false,
            required: false,
            stored: true
        },
        {
            name: "someDoubleValue",
            type: "tdouble",
            multiValued: false,
            indexed: true,
            required: false,
            stored: true
        }
    ]
}   
于 2016-03-14T07:45:22.920 回答