2013-10-04 58 views
2

假设我有一个测试应用程序代表一些朋友列表。该应用程序使用一个集合,其中的所有文件都采用以下格式:Solr索引的MongoDB集合

_id : ObjectId("someString"), 
name : "George", 
description : "some text", 
age : 35, 
friends : { 
    [ 
     { 
     name: "Peter", 
     age: 30 
     town: { 
        name_town: "Paris", 
        country: "France" 
       } 
     }, 
     { 
     name: "Thomas", 
     age: 25 
     town: { 
        name_town: "Berlin", 
        country: "Germany" 
       } 
     }, ...    // more friends 
    ] 
} 
...       // more documents 

我怎样才能在schema.xml中描述了这样的收藏?我需要制作方面的问题,如:“给我国家,乔治的朋友住在哪里”。另一个用例可能是 - “归还所有30岁以下的朋友。”等

我最初的想法是,以纪念这个schema.xml中定义“朋友”属性的文本字段:

<fieldType name="text_wslc" class="solr.TextField" positionIncrementGap="100"> 
.... 
<field name="friends" type="text_wslc" indexed="true" stored="true" /> 

,并尝试搜索如。文中的“年龄”和“30”字,但这不是一个非常可靠的解决方案。


请留下,不要在逻辑上形成良好的集合体系结构。这只是我刚刚面对的类似问题的一个例子。

任何帮助或想法将不胜感激。

编辑: 样品 '的schema.xml'

<?xml version="1.0" encoding="UTF-8" ?> 
<schema name="text-schema" version="1.5"> 
    <types> 
     <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/> 
     <fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0" /> 
     <fieldType name="trInt" class="solr.TrieIntField" precisionStep="0" omitNorms="true" /> 
     <fieldType name="text_p" class="solr.TextField" positionIncrementGap="100"> 
      <analyzer type="index"> 
       <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
       <filter class="solr.TrimFilterFactory"/> 
       <filter class="solr.WordDelimiterFilterFactory"/> 
       <filter class="solr.LowerCaseFilterFactory"/> 
      </analyzer> 
      <analyzer type="query"> 
       <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
       <filter class="solr.TrimFilterFactory"/> 
       <filter class="solr.WordDelimiterFilterFactory"/> 
       <filter class="solr.LowerCaseFilterFactory"/> 
      </analyzer> 
     </fieldType> 
    </types> 

    <fields> 
      <field name="_id" type="string" indexed="true" stored="true" required="true" /> 
      <field name="_version_" type="long" indexed="true" stored="true"/> 
      <field name="_ts" type="long" indexed="true" stored="true"/> 
      <field name="ns" type="string" indexed="true" stored="true"/>    
      <field name="description" type="text_p" indexed="true" stored="true" /> 
      <field name="name" type="text_p" indexed="true" stored="true" /> 
      <field name="age" type="trInt" indexed="true" stored="true" /> 
      <field name="friends" type="text_p" indexed="true" stored="true" />   <!-- Here is the problem - when the type is text_p, all fields are considered as a text; optimal solution would be something like "collection" tag to mark name_town and town as descendant of the field 'friends' but unfortunately, this is not how the solr works--> 

      <field name="town" type="text_p" indexed="true" stored="true"/> 
      <field name="name_town" type="string" indexed="true" stored="true"/>  
      <field name="town" type="string" indexed="true" stored="true"/> 
    </fields> 

    <uniqueKey>_id</uniqueKey> 

+1

好吧,如果你要坚持你的架构的想法,我没有看到你的需求的解决方案。您将需要连接功能,因为您希望执行诸如嵌套实体之类的操作。没有其他可靠的方法来查询这样的事情,而不会遇到更新 - 地狱。 – cheffe

回答

0

由于Solr的是文档为中心的,你需要扁平化,就像你可以下来。根据您提供的示例,我将创建一个schema.xml,如下所示。

<?xml version="1.0" encoding="UTF-8" ?> 
<schema name="friends" version="1.0"> 

    <fields> 
     <field name="id" 
      type="int" indexed="true" stored="true" multiValued="false" /> 
     <field name="name" 
      type="text" indexed="true" stored="true" multiValued="false" /> 
     <field name="description" 
      type="text" indexed="true" stored="true" multiValued="false" /> 
     <field name="age" 
      type="int" indexed="true" stored="true" multiValued="false" /> 
     <field name="town" 
      type="text" indexed="true" stored="true" multiValued="false" /> 
     <field name="townRaw" 
      type="string" indexed="true" stored="true" multiValued="false" /> 
     <field name="country" 
      type="text" indexed="true" stored="true" multiValued="false" /> 
     <field name="countryRaw" 
      type="string" indexed="true" stored="true" multiValued="false" /> 
     <field name="friends" 
      type="int" indexed="true" stored="true" multiValued="true" /> 
    </fields> 
    <copyField source="country" dest="countryRaw" /> 
    <copyField source="town" dest="townRaw" /> 

    <types> 
     <fieldType name="string" class="solr.StrField" sortMissingLast="true"/> 
     <fieldType name="int" class="solr.TrieIntField" 
      precisionStep="0" positionIncrementGap="0" /> 
     <fieldType name="text" class="solr.TextField" 
      positionIncrementGap="100"> 
      <analyzer> 
       <tokenizer class="solr.StandardTokenizerFactory" /> 
       <filter class="solr.LowerCaseFilterFactory" /> 
      </analyzer> 
     </fieldType> 
    </types> 
</schema> 

我会用这种方法来模拟每个人自己。两个人之间的关系通过朋友的属性来建模,后者转换为ID数组。因此,在索引时间,您需要获取一个人的所有朋友的ID并将其放入该字段。

大多数其他领域都很简单。有趣的是两个原始字段。既然你说过你想要面向国家,你将需要国家不变或优化分面。通常,字段的类型根据其目的而不同(搜索它们,修改它们,自动创建它们等)。在这种情况下国家和城市进行索引,就像他们中给出。

我们您的使用情况,

给我的国家,在那里乔治的朋友都住

然后可以做通过刻面。你可以查询

  • 乔治
  • 方面对countryRaw的ID

这样的查询看起来像q=friends:1&rows=0&facet=true&facet.field=countryRaw&facet.mincount=1

返回的所有文件(的人),他的朋友是30岁。

这一个更难。首先你需要Solr's join feature。您需要在您的solrconfig.xml中进行配置。

<config> 
    <!-- loads of other stuff --> 
    <queryParser name="join" class="org.apache.solr.search.JoinQParserPlugin" /> 
    <!-- loads of other stuff --> 
</config> 

将根据连接查询看起来像这样q={!join from=id to=friends}age:[30 TO *]

这说明如下

  • age:[30 TO *]您搜索是30岁以上的老年人
  • 然后你把所有的人他们的身份证,并加入所有其他朋友attibute
  • 这将返回所有人hav e通过其朋友属性中的初始查询匹配的ID

由于我没有写下这个问题,所以您可能会看看我的github上的solrsample项目。我已经有添加了一个测试用例涉及一个问题:

https://github.com/chriseverty/solrsample/blob/master/src/main/java/de/cheffe/solrsample/FriendJoinTest.java

+0

Cheffe,感谢您准确回答的问题。但也许我并没有真正强调模式不应该被改变。假设说明了模式。你能找到任何可能的解决方案如何才能访问指定的数据? – user1949763

+0

user1949763,在这种情况下,我需要更多的schema.xml。最好是包含'types'的整个''元素。 – cheffe

+0

我将'schema.xml'定义添加到原始文章中。但是这些定义很模糊,因为我无法克服这个限制。 – user1949763