mongodb lbs java_LBS JAVA Spring mongoDB

基本介绍

位置服务(LBS)解决的主要问题是当前位置周围某个范围内的人或场所.

在传统的解决方案,开发人员需要根据复杂的几何运算与大量的SQL语句进行查找,这无疑加大的开发人员的开发难度.

现在我们需要更为方便的解决方案,MongoDB为我们完美解决此类LBS问题.此篇文章也主要使用SpringData,将spring与MongoDB进行整合.

二维地图

MongoDB目前支持二维的地图查询,查询区域包括圆形与矩形,距离单位包括MILES,KILOMETERS,NEUTRAL,下面的示例演示距离单位为NEUTRAL,而实际生产应用中则会用到MILES与KILOMETERS.

MongoDB示例

首先定义一个位置集合,给定a,b,c,d节点.

1

2

3

4

5

6

7

8

>

db

.

createCollection

(

"location"

)

{

"ok"

:

1

}

>

db

.

location

.

save

(

{

_id

:

"A"

,

position

:

[

0.1

,

-

0.1

]

}

)

>

db

.

location

.

save

(

{

_id

:

"B"

,

position

:

[

1.0

,

1.0

]

}

)

>

db

.

location

.

save

(

{

_id

:

"C"

,

position

:

[

0.5

,

0.5

]

}

)

>

db

.

location

.

save

(

{

_id

:

"D"

,

position

:

[

-

0.5

,

-

0.5

]

}

)

接着指定location索引

1

db

.

location

.

ensureIndex

(

{

position

:

"2d"

}

)

现在我们可以进行简单的GEO查询

查询point(0,0),半径0.7附近的点

1

2

3

4

>

db

.

location

.

find

(

{

position

:

{

$near

:

[

0

,

0

]

,

$maxDistance

:

0.7

}

}

)

{

"_id"

:

"A"

,

"position"

:

[

0.1

,

-

0.1

]

}

查询point(0,0),半径0.75附近的点

1

2

3

4

5

6

>

db

.

location

.

find

(

{

position

:

{

$near

:

[

0

,

0

]

,

$maxDistance

:

0.75

}

}

)

{

"_id"

:

"A"

,

"position"

:

[

0.1

,

-

0.1

]

}

{

"_id"

:

"C"

,

"position"

:

[

0.5

,

0.5

]

}

{

"_id"

:

"D"

,

"position"

:

[

-

0.5

,

-

0.5

]

}

我们可以看到半径不一样,查询出的点也不一样,因为c点坐标为[0.5,0.5],c至圆点的距离根据勾股定理可得出Math.sqrt(0.25 +0.25) ≈ 0.707,所以最大距离0.7时查找不到你要的点.

查询[0.25, 0.25], [1.0,1.0]区域附近的点

1

2

3

4

5

>

db

.

location

.

find

(

{

position

:

{

$within

:

{

$box

:

[

[

0.25

,

0.25

]

,

[

1.0

,

1.0

]

]

}

}

}

)

{

"_id"

:

"C"

,

"position"

:

[

0.5

,

0.5

]

}

{

"_id"

:

"B"

,

"position"

:

[

1

,

1

]

}

Spring Data示例

spring data为我们封装了mongoDB访问接口与实现,我们可以像使用hibernateTemplate一样使用mongoTemplate.

首先我们需要像hibernate一样定义pojo类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

import

org

.

springframework

.

data

.

annotation

.

Id

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

mapping

.

Document

;

@Document

(

collection

=

"location"

)

public

class

Location

{

@Id

private

String

id

;

private

double

[

]

position

;

/** getter setter hashcode equals toString ...  */

}

定义Dao,我们先使用最简单的mongoTemplate来实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

import

java

.

util

.

List

;

import

org

.

springframework

.

beans

.

factory

.

annotation

.

Autowired

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

MongoTemplate

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Box

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Point

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

query

.

Criteria

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

query

.

Query

;

import

org

.

springframework

.

stereotype

.

Repository

;

@Repository

public

class

LocationDao

{

@Autowired

MongoTemplate

mongoTemplate

;

public

List

findCircleNear

(

Point

point

,

double

maxDistance

)

{

return

mongoTemplate

.

find

(

new

Query

(

Criteria

.

where

(

"position"

)

.

near

(

point

)

.

maxDistance

(

maxDistance

)

)

,

Location

.

class

)

;

}

public

List

findBoxNear

(

Point

lowerLeft

,

Point

upperRight

)

{

return

mongoTemplate

.

find

(

new

Query

(

Criteria

.

where

(

"position"

)

.

within

(

new

Box

(

lowerLeft

,

upperRight

)

)

)

,

Location

.

class

)

;

}

}

最后我们写一个test类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

import

java

.

util

.

Collection

;

import

java

.

util

.

List

;

import

org

.

junit

.

Before

;

import

org

.

junit

.

Test

;

import

org

.

junit

.

runner

.

RunWith

;

import

org

.

springframework

.

beans

.

factory

.

annotation

.

Autowired

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

MongoTemplate

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Point

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

index

.

GeospatialIndex

;

import

org

.

springframework

.

test

.

context

.

ContextConfiguration

;

import

org

.

springframework

.

test

.

context

.

junit4

.

SpringJUnit4ClassRunner

;

@RunWith

(

SpringJUnit4ClassRunner

.

class

)

@ContextConfiguration

(

locations

=

{

"classpath:/applicationContext.xml"

,

"classpath:/application-mongo.xml"

}

)

public

class

MongoDBTest

{

@Autowired

LocationDao

locationDao

;

@Autowired

MongoTemplate

template

;

@Before

public

void

setUp

(

)

{

// 等同db.location.ensureIndex( {position: "2d"} )

template

.

indexOps

(

Location

.

class

)

.

ensureIndex

(

new

GeospatialIndex

(

"position"

)

)

;

// 初始化数据

template

.

save

(

new

Location

(

"A"

,

0.1

,

-

0.1

)

)

;

template

.

save

(

new

Location

(

"B"

,

1

,

1

)

)

;

template

.

save

(

new

Location

(

"C"

,

0.5

,

0.5

)

)

;

template

.

save

(

new

Location

(

"D"

,

-

0.5

,

-

0.5

)

)

;

}

@Test

public

void

findCircleNearTest

(

)

{

List

locations

=

locationDao

.

findCircleNear

(

new

Point

(

0

,

0

)

,

0.7

)

;

print

(

locations

)

;

System

.

err

.

println

(

"-----------------------"

)

;

locations

=

locationDao

.

findCircleNear

(

new

Point

(

0

,

0

)

,

0.75

)

;

print

(

locations

)

;

}

@Test

public

void

findBoxNearTest

(

)

{

List

locations

=

locationDao

.

findBoxNear

(

new

Point

(

0.2

,

0.2

)

,

new

Point

(

1

,

1

)

)

;

print

(

locations

)

;

}

public

static

void

print

(

Collection

locations

)

{

for

(

Location

location

:

locations

)

{

System

.

err

.

println

(

location

)

;

}

}

}

大家可以看到运行结果与我们直接在mongoDB上的一样.

MongoRepository

MongoRepository提供了对MongoTemplate的封装与实现,只需要继承MongoRepository接口,填上对应的bean类与ID类型,无需实现里面的方法即可使用,先看代码.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Box

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Distance

;

import

org

.

springframework

.

data

.

mongodb

.

core

.

geo

.

Point

;

import

org

.

springframework

.

data

.

mongodb

.

repository

.

MongoRepository

;

public

interface

LocationRepository

extends

MongoRepository

<

Location

,

String

>

{

List

findByPositionNear

(

Point

p

,

Distance

d

)

;

List

findByPositionWithin

(

Box

b

)

;

}

然后在test类中引用此类即可,MongoRepository实现了最基本的增删改查的功能,要想增加额外的查询方法,可以按照以下规则定义接口的方法.

自定义查询方法,格式为findBy+字段名+方法名,方法传进的参数即字段的值,此外还支持分页查询,通过传进一个Pageable对象会返回Page集合.

原理相信大家也很清楚,即aop,细节就不说拉.

小提示

near与within方法区别,near方法查询后会对结果集对distance进行排序且有大小限制,而within是无序的也无大小限制.

如果大家有新发现,也可回帖,我会及时补充.

你可能感兴趣的:(mongodb,lbs,java)