Wetts's blog

Stay Hungry, Stay Foolish.

0%

基本查询

  • q - 查询字符串,这个是必须的。如果查询所有*:* ,根据指定字段查询(Name:张三 AND Address:北京)
  • fq - (filter query)过虑查询,作用:在q查询符合结果中同时是fq查询符合的,例如:q=Name:张三&fq=createDate:[2014-06-18 TO 2015-12-18],找关键字”张三”,并且CreateDate是查询2014-06-18到2015-12-18之间的数据
  • fl - 指定返回那些字段内容,用逗号或空格分隔多个。
  • start - 返回第一条记录在完整找到结果中的偏移位置,0开始,一般分页用。
  • rows - 指定返回结果最多有多少条记录,配合start来实现分页。
  • sort - 排序,格式:sort=+<desc|asc>[,+<desc|asc>]… 。示例:(score desc, price asc)表示先 “score” 降序, 再 “price” 升序,默认是相关性降序。
  • wt - (writer type)指定输出格式,可以有 xml, json, php, phps。
  • fl表示索引显示那些field( *表示所有field,如果想查询指定字段用逗号或空格隔开(如:Name,SKU,ShortDescription或Name SKU ShortDescription【注:字段是严格区分大小写的】))
  • q.op 表示q 中 查询语句的 各条件的逻辑操作 AND(与) OR(或)

Solr的检索运算符

  1. “:” 指定字段查指定值,如返回所有值*:*
  2. “?” 表示单个任意字符的通配
  3. *” 表示多个任意字符的通配(不能在检索的项开始使用*或者?符号)
  4. ” 表示模糊检索,如检索拼写类似于”roam”的项这样写:roam将找到形如foam和roams的单词;roam~0.8,检索返回相似度在0.8以上的记录。
  5. 邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
  6. “^” 控制相关度检索,如检索jakarta apache,同时希望去让”jakarta”的相关度更加好,那么在其后加上”^”符号和增量值,即jakarta^4 apache
  7. 布尔操作符AND、||
  8. 布尔操作符OR、&&
  9. 布尔操作符NOT、!、- (排除操作符不能单独与项使用构成查询)
  10. “+” 存在操作符,要求符号”+”后的项必须在文档相应的域中存在
  11. ( ) 用于构成子查询
  12. [] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO 200710]
  13. {} 不包含范围检索,如检索某时间段记录,不包含头尾
    date:{200707 TO 200710}
  14. / 转义操作符,特殊字符包括+ - && || ! ( ) { } [ ] ^ ” ~ * ? : /

注:①“+”和”-“表示对单个查询单元的修饰,and 、or 、 not 是对两个查询单元是否做交集或者做差集还是取反的操作的符号

比如:AB:china +AB:america,表示的是AB:china忽略不计可有可无,必须满足第二个条件才是对的,而不是你所认为的必须满足这两个搜索条件

如果输入:AB:china AND AB:america,解析出来的结果是两个条件同时满足,即+AB:china AND +AB:america或+AB:china +AB:america

总而言之,查询语法: 修饰符 字段名:查询关键词 AND/OR/NOT 修饰符 字段名:查询关键词

高亮

  • h1 是否高亮,hl=true,表示采用高亮
  • hl.fl 设定高亮显示的字段,用空格或逗号隔开的字段列表。要启用某个字段的highlight功能,就得保证该字段在schema中是stored。如果该参数未被给出,那么就会高亮默认字段 standard handler会用df参数,dismax字段用qf参数。你可以使用星号去方便的高亮所有字段。如果你使用了通配符,那么要考虑启用hl.requiredFieldMatch选项。
  • hl.requireFieldMatch 如果置为true,除非用hl.fl指定了该字段,查询结果才会被高亮。它的默认值是false。
  • hl.usePhraseHighlighter 如果一个查询中含有短语(引号框起来的)那么会保证一定要完全匹配短语的才会被高亮。
  • hl.highlightMultiTerm 如果使用通配符和模糊搜索,那么会确保与通配符匹配的term会高亮。默认为false,同时hl.usePhraseHighlighter要为true。
  • hl.fragsize 返回的最大字符数。默认是100.如果为0,那么该字段不会被fragmented且整个字段的值会被返回。

分组

官方wiki:http://wiki.apache.org/solr/SimpleFacetParameters#Facet_Fields_and_Facet_Queries,

这是facet的官方wiki,里面有facet各个参数的详细说明。所以这里只说一些常用的。

Facet是Solr的核心搜索功能,主要是导航(Guided Navigation)、参数化查询(Paramatic Search)。Facet的主要好处是在搜索的同时,可以按照Facet条件进行分组统计,给出导航信息,改善搜索体验。

Facet主要分为:Field Facet 和 Date Facet 两大类

Field Facet

  • facet 参数字段必须被索引
  • facet=on 或 facet=true
  • facet.field 分组的字段
  • facet.prefix 表示Facet字段前缀
  • facet.limit Facet字段返回条数
  • facet.offict 开始条数,偏移量,它与facet.limit配合使用可以达到分页的效果
  • facet.mincount Facet字段最小count,默认为0
  • facet.missing 如果为on或true,那么将统计那些Facet字段值为null的记录
  • facet.sort 表示 Facet 字段值以哪种顺序返回 .格式为 true(count)|false(index,lex),true(count) 表示按照 count 值从大到小排列,false(index,lex) 表示按照字段值的自然顺序 (字母 , 数字的顺序 ) 排列 . 默认情况下为 true(count)

Date Facet

对日期类型的字段进行 Facet. Solr 为日期字段提供了更为方便的查询统计方式 .注意 , Date Facet的字段类型必须是 DateField( 或其子类型 ). 需要注意的是 , 使用 Date Facet 时 , 字段名 , 起始时间 , 结束时间 , 时间间隔这 4 个参数都必须提供 .

  • facet.date 该参数表示需要进行 Date Facet 的字段名 , 与 facet.field 一样 , 该参数可以被设置多次 , 表示对多个字段进行 Date Facet.
  • facet.date.start 起始时间 , 时间的一般格式为 ” 2015-12-31T23:59:59Z”, 另外可以使用 ”NOW”,”YEAR”,”MONTH” 等等 ,
  • facet.date.end 结束时间
  • facet.date.gap 时间间隔,如果 start 为 2015-1-1,end 为 2016-1-1,gap 设置为 ”+1MONTH” 表示间隔1 个月 , 那么将会把这段时间划分为 12 个间隔段 .
  • facet.date.hardend 表示 gap 迭代到 end 时,还剩余的一部分时间段,是否继续去下一个间隔. 取值可以为 true|false, 默认为 false.

例 start 为 2015-1-1,end 为 2015-12-21,gap 为 ”+1MONTH”, 如果hardend 为 false,则,最后一个时间段为 2015-12-1 至 2016-1-1; 反之,如果 hardend 为 true,则,最后一个时间段为 2015-12-1 至 2015-12-21.

注意:Facet的字段必须被索引,无需分词,无需存储。无需分词是因为该字段的值代表了一个整体概念,无需存储是因为一般而言用户所关心的并不是该字段的具体值,而是作为对查询结果进行分组的一种手段,给出相关的分组信息,从而改善搜索体验。

Solr查询语法

  1. 最普通的查询,比如查询姓张的人( Name:张),如果是精准性搜索相当于SQL SERVER中的LIKE搜索这需要带引号(””),比如查询含有北京的(Address:”北京”)
  2. 多条件查询,注:如果是针对单个字段进行搜索的可以用(Name:搜索条件加运算符(OR、AND、NOT) Name:搜索条件),比如模糊查询( Name:张 OR Name:李)单个字段多条件搜索不建议这样写,一般建议是在单个字段里进行条件筛选,如(Name:张 OR 李),多个字段查询(Name:张 + Address:北京 )
  3. 排序,比如根据姓名升序(Name asc),降序(Name desc)

查询结果匹配

一般情况下solr默认是进行拆分匹配查询的,如:“苏小小”拆成“苏”,“小”,“小”等。但是如果要进行完全匹配 “苏小小” 可以将关键词用双引号括起来如下:

例如 :http://localhost:8081/solr/select/?q=name:"苏小小"&version=2.2&start=0&rows=10&indent=on&sort=cDate desc&hl=true&hl.fl=content

注意:如果在搜索的目标上有一句话中包含这个关键字,那么这段话也会被搜索到,如:“很久很久以前苏小小就是很出名了”。千万不要以为只是关键字的内容才能搜索到。

  • 首先创建一个core。

  • conf下创建文件。

    • managed-schema/schema.xml 这个是索引的结构定义的文件,定义了字段的名称,类型,索引与否,分词方法等
    • solrconfig.xml 这个文件是solr的基础文件,主要配置了solr的各种web请求处理器、日志、缓存等
    • db-data-config.xml 这个是配置连接mysql数据库的配置信息,名称可以自己修改,也是放在conf 下面(没有可以自行创建)

managed-schema/schema.xml

1
2
<field name="name" type="string" indexed="true" stored="false" />
<field name="loginName" type="string" indexed="true" stored="false" />

solrconfig.xml

1
2
<lib dir="/Users/wetts/.m2/repository/mysql/mysql-connector-java/5.1.38" regex=".*\.jar" />
<lib dir="${solr.install.dir}/libexec/dist/" regex="solr-dataimporthandler-.*\.jar" />
1
2
3
4
5
<requestHandler name="/dataimport" class="solr.DataImportHandler">
<lst name="defaults">
<str name="config">db-data-config.xml</str>
</lst>
</requestHandler>

db-data-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/jeesite"
user="root"
encoding="UTF-8"
password=""/>
<document>
<entity name="sys_user" processor="SqlEntityProcessor" pk="id"
query="select id,login_name,name from sys_user">
<field name="id" column="id" />
<field name="loginName" column="login_name" />
<field name="name" column="name" />
</entity>
</document>
</dataConfig>

安装Solr

1
brew install solr

启动Solr

1
solr start

启动Solr案例

1
solr -e dih

创建一个core

1
solr create -c <core的名称>

停止Solr

1
solr stop -all

批量关闭php进程

1
ps -ef | grep php |grep -v grep |cut -c 9-15 |xargs sudo kill -9

grep -v grep是在列出的进程中去除含有关键字“grep”的进程。

cut -c 9-15是截取输入行的第9个字符到第15个字符,而这正好是进程号PID。

xargs kill -9中的xargs命令是用来把前面命令的输出结果(PID)作为“kill -9”命令的参数,并执行该令。

Mongodb 中的 mongoexport 工具可以把一个 collection 导出成 JSON 格式或 CSV 格式的文件。

1
2
3
4
5
6
7
8
E:\_soft\MongoDB\Server\3.2\bin\mongoexport
-v
--host 123.57.25.147:27017
-d "moments"
-c "post"
--out F:\post.json
--type json
--query "{ \"createTime\" : { \"$gt\" : ISODate(\"2017-01-19T00:00:00.000+08:00\"), \"$lt\" : ISODate(\"2017-01-20T00:00:00.000+08:00\") } }"

参数说明:

  • -h:指明数据库宿主机的 IP
  • -u:指明数据库的用户名
  • -p:指明数据库的密码
  • -d:指明数据库的名字
  • -c:指明 collection 的名字
  • -f:指明要导出那些列
  • -o:指明到要导出的文件名
  • -q:指明导出数据的过滤条件

注释

  1. 不恰当的信息

让注释传达本该更好地在源代码控制系统、问题追踪系统或任何其他记录系统中保持的信息,是不恰当的。例如,修改历史记录只会用大量过时而无趣的文本搞乱源代码文件。通常,作者、最后修改时间、SPR数等元数据不该在注释中出现。注释只应该描述有关代码和设计的技术性信息。

  1. 废弃的注释

过时、无关或不正确的注释就是废弃的注释。注释会很快过时。最好别编写将被废弃的注释。如果发现废弃的注释,最好尽快更新或删除。

  1. 冗余注释

如果注释描述的是某种充分自我描述了的东西,那么注释就是多余的。例如:

1
i++; // increment i

另一个例子是除函数签名之外什么也没多说(或少说)的Javadoc:
1
2
3
4
5
6
/**
* @param sellRequest
* @return
* @throws ManagedComponentException
*/
public SellReponse beginSellItem(SellRequest sellRequest) throws ManagedComponentException

  1. 糟糕的注释

如果要编写一条注释,就花时间保证写出最好的注释,字斟句酌。使用正确的语法和拼写。别闲扯,别画蛇添足,保持简洁。

  1. 注释掉的代码

看到注释掉的代码,就删除它!源代码控制系统会记得它,如果有人真的需要,可以签出比较前的版本。

函数

  1. 过多的参数

函数的参数数量应该少。没参数最好,一个次之,两个、三个再次之。三个以上的参数非常值得质疑,应坚决避免。

  1. 输出参数

输出参数违反直觉。读者期望参数用于输入而非输出。如果函数非要修改什么东西的状态不可,就修改它所在对象的状态好了。

  1. 标识参数

布尔值参数大声宣告函数做了不止一件事。它们令人迷惑,应该消灭掉。

  1. 死函数

永不被调用的方法应该丢弃。

TDD(Test-Driven Development):测试驱动开发,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。

TDD三定律:

  1. 在编写不能通过的单元测试前,不可编写生产代码。
  2. 只可编写刚好无法通过的单元测试,不能编译也算不能通过。
  3. 只可编写刚好足以通过当前失败测试的生产代码。

这样测试代码量足以匹敌生产代码量,导致令人生畏的管理问题。

测试代码和生产代码一样重要。它该像生产代码一般保持整洁。

整洁的测试,三个要素:可读性、可读性和可读性。

每个测试函数只测试一个概念。

整洁的测试还遵循一下5条规则(F.I.R.S.T):

  • 快速(Fast):测试应该够快。测试运行缓慢,你就不会想要频繁地运行它。
  • 独立(Independent):测试应该相互独立。某个测试不应为下一个测试设定条件。
  • 可重复(Repeatable):测试应当可在任何环境中重复通过。
  • 自足验证(Self-Validating):测试应该有布尔值输出。
  • 及时(Timely):测试应及时编写。

使用第三方代码

在接口提供者和使用者之间,存在与生俱来的张力。第三方程序包和框架提供者追求普适性,这样就能在多个环境中工作,吸引广泛的用户。而使用者则想要集中满足特定需求的接口。这种张力会导致系统边界上出现问题。

以java.util.Map为例。应用程序可能构造一个Map对象并传递它。我们的初衷可能是Map对象的所有接收者都不要删除映射图中的任何东西。但是Map中正好有一个clear()方法。Map的任何使用者都能清楚映射图。或许设计惯例是Map中只能保存特定的类型,但Map并不会可靠地约束存于其中的对象的类型。使用者可随意往Map中塞入任何类型的条目。

可以通过泛型来规定传入参数的类型。但是超出所需/所愿的功能问题,仍未得到解决。

在系统中不受限制的传递Map<Integer, Sensors>的实体,意味着当到Map的接口被修改时,有许多地方都要跟着改。你或许会认为这样的改动不太可能发生,不过,当Java 5加入对泛型的支持时,的确发生了改动。

使用Map的更整洁的方式大概如下。Sensors的用户不必关心是否用了泛型,那将是实现细节才关心的。

1
2
3
4
5
6
7
public class Sensors {
private Map sensors = new HashMap();

public Sensors getById(String id) {
return (Sensors) sensors.get(id);
}
}

边界上的接口(Map)是隐藏的。它能随来自应用程序其他部分的极小的影响而变动。对泛型的使用不再是一个大问题,因为转换和类型管理是在Sensors类内部处理的。

我们并不建议总是以这种方式封装Map的使用。我们建议不要将Map(或者边界上的其他接口)在系统中传递。如果你使用类似Map这样的边界接口,就把它保留在类或近亲类中。避免从公共API中返回边界接口,或将边界接口作为参数传递给公共API。


我们通过代码中少数几处引用第三方边界接口的位置来管理第三方边界。可以像我们对待Map那样包装它们,也可以使用Adapter模式将我们的接口转换为第三方提供的接口。采用这两种方式,代码都能更好地与我们沟通,在边界两边推动内部一致的用法,当第三方代码有改动时修改点也会更少。

遵循标准的Java约定,类应该从一组变量列表开始。如果有公共静态变量,应该先出现。然后是私有静态变量,以及私有实体变量。很少会有公共变量。

  • 类应该短小

    • 单一权责原则

      系统应该是由许多短小的类而不是少量巨大的类组成。每个小类封装一个职责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为。

    • 内聚

      类应该只有少量实体变量。类中的每个方法都应该操作一个或多个这种变量。通常而言,方法操作的变量越多,就越黏聚在类上。如果一个类中的每个变量都被每个方法所使用,则该类具有最大的内聚性。

      保持内聚性会得到许多短小的类

  • -XX:MetaspaceSize,是分配给类元数据空间(以字节计)的初始大小(Oracle逻辑存储上的初始高水位,the initial high-water-mark ),此值为估计值。MetaspaceSize的值设置的过大会延长垃圾回收时间。垃圾回收过后,引起下一次垃圾回收的类元数据空间的大小可能会变大。
  • -XX:MaxMetaspaceSize,是分配给类元数据空间的最大值,超过此值就会触发Full GC,此值默认没有限制,但应取决于系统内存的大小。JVM会动态地改变此值。

除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:

  • -XX:MinMetaspaceFreeRatio,表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最小比例,不够就会导致垃圾回收。
  • -XX:MaxMetaspaceFreeRatio,表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最大比例,不够就会导致垃圾回收。