new realtime search with lucene - berlin...

87
Realtime Search with Lucene Michael Busch @michibusch [email protected] [email protected] 1 Monday, June 7, 2010

Upload: others

Post on 16-Oct-2020

17 views

Category:

Documents


0 download

TRANSCRIPT

Page 2: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

‣ Introduction

- Near-realtime Search (NRT)

- Searching DocumentsWriter’s RAM buffer

- Sequence IDs

- Twitter prototype

- Roadmap

2Monday, June 7, 2010

Page 3: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Introduction

3Monday, June 7, 2010

Page 4: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Introduction

• Lucene made great progress towards realtime search with the Near-realtime search feature (NRT) added in 2.9

• NRT reduces search latency (time it takes until a document becomes searchable) significantly, using the new IndexWriter.getReader()

• Drawback of NRT: If getReader() is called frequently, indexing performance decreases significantly

• New approach: Searching on IndexWriter’s/DocumentsWriter’s in-memory buffer directly

4Monday, June 7, 2010

Page 5: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

- Introduction

‣ Near-realtime Search (NRT)

- Searching DocumentsWriter’s RAM buffer

- Sequence IDs

- Twitter prototype

- Roadmap

5Monday, June 7, 2010

Page 6: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Near-realtime Search (NRT)

6Monday, June 7, 2010

Page 7: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

• Lucene is an incremental indexer - documents can be added to an existing, searchable index

• Lucene writes “segments”, which are small indexes itself

• A Lucene index consists of one or more segments

• Small segments are merged into larger ones to limit total number of segments per index

7Monday, June 7, 2010

Page 8: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 1

• After a segment is written and committed (triggered by IndexWriter.commit() or IndexWriter.close()) it is visible to IndexReaders

8Monday, June 7, 2010

Page 9: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 1 Segment 2

• After a segment is written and committed (triggered by IndexWriter.commit() or IndexWriter.close()) it is visible to IndexReaders

• New segments can be written, while IndexReaders execute queries on older segments

9Monday, June 7, 2010

Page 10: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 1 Segment 2 Segment 3

• After a segment is written and committed (triggered by IndexWriter.commit() or IndexWriter.close()) it is visible to IndexReaders

• New segments can be written, while IndexReaders execute queries on older segments

10Monday, June 7, 2010

Page 11: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 1 Segment 2 Segment 3

Segment 4

Segment merging(mergeFactor=3)

11Monday, June 7, 2010

Page 12: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 4

Segment 1 Segment 2 Segment 3

Delete old segments

12Monday, June 7, 2010

Page 13: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 5Segment 4

Segment 1 Segment 2 Segment 3

13Monday, June 7, 2010

Page 14: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Incremental Indexing

Segment 5 Segment 6Segment 4

Segment 1 Segment 2 Segment 3

14Monday, June 7, 2010

Page 15: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Committing an index segment

• Flush in-memory data structures to index location (usually on disk)

• Possibly trigger a segment merge

• Synchronize segment files, which forces the OS to flush those files from the FS cache to the physical disk (this can be an expensive operation)

• Append an entry to segments_x file and write new segment_x+1 file

• IndexWriter.close() might have to wait for in-flight segment merges to complete (this can be very expensive)

15Monday, June 7, 2010

Page 16: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Near-realtime search (NRT)

• NRT tries to avoid the two most expensive aspects of segment committing: file handle sync calls and waiting for segment merge completion

• IndexWriter.getReader() can be called to obtain an IndexReader, that can query flushed, not-yet-committed segments

• Reduces indexing latency significantly, and IndexWriters don’t have to be closed to (re)open IndexReaders

• Disadvantage: getReader() triggers a flush of the in-memory data structures

16Monday, June 7, 2010

Page 17: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

A little bit Lucene history: LUCENE-843

• Indexer was rewritten with LUCENE-843 patch (released in 2.3)

• Indexing performance improved by 5x-10x (!!)

• Before, each document was inverted and encoded as its own segment

• These tiny single-doc segments were merged with Lucene’s standard SegmentMerger

• LUCENE-843 introduced class DocumentsWriter, which can take a large number of docs and invert them into a single segment

• Dramatic improvements in memory consumption and indexing performance

17Monday, June 7, 2010

Page 18: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Near-realtime search (NRT)

• IndexWriter.getReader() triggers DocumentsWriter to flush its in-memory data structures into a segment every time it’s called

• If called very frequently (desired in realtime search), it results in a similar behavior as before LUCENE-843

18Monday, June 7, 2010

Page 19: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

- Introduction

- Near-realtime Search (NRT)

‣ Searching DocumentsWriter’s RAM buffer

- Sequence IDs

- Twitter prototype

- Roadmap

19Monday, June 7, 2010

Page 20: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Searching DocumentsWriter’s RAM buffer

20Monday, June 7, 2010

Page 21: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Goals

• Goal 1:Allow IndexReaders to search on DocumentsWriter’s RAM buffer, while documents are being appended simultaneously to the same data structures

• Goal 2:Maintain high indexing performance with large RAM buffer, and independent of the query load

• Goal 3:Opening a RAM IndexReader should be so cheap, so that a new reader can be opened for every query (drops latency close to zero)

21Monday, June 7, 2010

Page 22: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

• Already committed to Lucene’s trunk

• Changes how per-term data is stored in RAM

22Monday, June 7, 2010

Page 23: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Inverted Index

1 The old night keeper keeps the keep in the town

2 In the big old house in the big old gown.

3 The house in the town had the big old keep

4 Where the old night keeper never did sleep.

5 The night keeper keeps the keep in the night

6 And keeps in the dark and sleeps in the light.

Table with 6 documents

Example from:Justin Zobel , Alistair Moffat, Inverted files for text search engines, ACM Computing Surveys (CSUR)v.38 n.2, p.6-es, 2006

23Monday, June 7, 2010

Page 24: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Inverted Index

1 The old night keeper keeps the keep in the town

2 In the big old house in the big old gown.

3 The house in the town had the big old keep

4 Where the old night keeper never did sleep.

5 The night keeper keeps the keep in the night

6 And keeps in the dark and sleeps in the light.

term freqand 1 <6>big 2 <2> <3>

dark 1 <6>did 1 <4>

gown 1 <2>had 1 <3>

house 2 <2> <3>in 5 <1> <2> <3> <5> <6>

keep 3 <1> <3> <5>keeper 3 <1> <4> <5>keeps 3 <1> <5> <6>light 1 <6>

never 1 <4>night 3 <1> <4> <5>old 4 <1> <2> <3> <4>

sleep 1 <4>sleeps 1 <6>

the 6 <1> <2> <3> <4> <5> <6>town 2 <1> <3>where 1 <4>

Table with 6 documents

Dictionary and posting lists24Monday, June 7, 2010

Page 25: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Inverted Index

1 The old night keeper keeps the keep in the town

2 In the big old house in the big old gown.

3 The house in the town had the big old keep

4 Where the old night keeper never did sleep.

5 The night keeper keeps the keep in the night

6 And keeps in the dark and sleeps in the light.

term freqand 1 <6>big 2 <2> <3>

dark 1 <6>did 1 <4>

gown 1 <2>had 1 <3>

house 2 <2> <3>in 5 <1> <2> <3> <5> <6>

keep 3 <1> <3> <5>keeper 3 <1> <4> <5>keeps 3 <1> <5> <6>light 1 <6>

never 1 <4>night 3 <1> <4> <5>old 4 <1> <2> <3> <4>

sleep 1 <4>sleeps 1 <6>

the 6 <1> <2> <3> <4> <5> <6>town 2 <1> <3>where 1 <4>

Table with 6 documents

Dictionary and posting lists

Query: keeper

25Monday, June 7, 2010

Page 26: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Inverted Index

1 The old night keeper keeps the keep in the town

2 In the big old house in the big old gown.

3 The house in the town had the big old keep

4 Where the old night keeper never did sleep.

5 The night keeper keeps the keep in the night

6 And keeps in the dark and sleeps in the light.

term freqand 1 <6>big 2 <2> <3>

dark 1 <6>did 1 <4>

gown 1 <2>had 1 <3>

house 2 <2> <3>in 5 <1> <2> <3> <5> <6>

keep 3 <1> <3> <5>keeper 3 <1> <4> <5>keeps 3 <1> <5> <6>light 1 <6>

never 1 <4>night 3 <1> <4> <5>old 4 <1> <2> <3> <4>

sleep 1 <4>sleeps 1 <6>

the 6 <1> <2> <3> <4> <5> <6>town 2 <1> <3>where 1 <4>

Table with 6 documents

Dictionary and posting lists

Query: keeper

26Monday, June 7, 2010

Page 27: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Inverted Index

1 The old night keeper keeps the keep in the town

2 In the big old house in the big old gown.

3 The house in the town had the big old keep

4 Where the old night keeper never did sleep.

5 The night keeper keeps the keep in the night

6 And keeps in the dark and sleeps in the light.

term freqand 1 <6>big 2 <2> <3>

dark 1 <6>did 1 <4>

gown 1 <2>had 1 <3>

house 2 <2> <3>in 5 <1> <2> <3> <5> <6>

keep 3 <1> <3> <5>keeper 3 <1> <4> <5>keeps 3 <1> <5> <6>light 1 <6>

never 1 <4>night 3 <1> <4> <5>old 4 <1> <2> <3> <4>

sleep 1 <4>sleeps 1 <6>

the 6 <1> <2> <3> <4> <5> <6>town 2 <1> <3>where 1 <4>

Table with 6 documents

Dictionary and posting lists

Per term we store different kinds of metadata: text pointer, frequency, postings pointer, etc.

27Monday, June 7, 2010

Page 28: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

class PostingList

int textPointer;int postingsPointer;int frequency;...

• Term hashtable is an array of these objects: PostingList[] termsHash

• For each unique term in a segment we need an instance; this results in a very large number of objects that are long-living, i.e. the garbage collecter can’t remove them quickly (they need to stay in memory until the segment is flushed)

• With a searchable RAM buffer we want to flush much less often and allow DocumentsWriter to fill up the available memory

28Monday, June 7, 2010

Page 29: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

class PostingList

int textPointer;int postingsPointer;int frequency;...

• Having a large number of long-living objects is very expensive in Java, especially when the default mark-and-sweep garbage collector is used

• The mark phase of GC becomes very expensive, because all long-living objects in memory have to be checked

• We need to reduce the number of objects to improve GC performance!-> Parallel posting arrays

29Monday, June 7, 2010

Page 30: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

PostingList[]

textPointer;

frequency;

intintint

postingsPointer;

30Monday, June 7, 2010

Page 31: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

termIDint[] textPointer; frequency;postingsPointer;

int[] int[] int[]

0123456

31Monday, June 7, 2010

Page 32: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

0

termIDint[] textPointer; frequency;postingsPointer;

int[] int[] int[]

t0 p0 f00123456

32Monday, June 7, 2010

Page 33: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

1

0

termIDint[] textPointer; frequency;postingsPointer;

int[] int[] int[]

t0

t1

p0

p1

f0

f1

0123456

33Monday, June 7, 2010

Page 34: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays

1

0

2

termIDint[] textPointer; frequency;postingsPointer;

int[] int[] int[]

t0

t1

t2

p0

p1

p2

f0

f1

f2

0123456

• Total number of objects is now greatly reduced and is constant and independent of number of unique terms

• With parallel arrays we safe 28 bytes per unique term -> 41% savings compared to PostingList object

34Monday, June 7, 2010

Page 35: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays - Performance

• Performance experiments: Index 1M wikipedia docs

1) -Xmx2048M, indexWriter.setMaxBufferSizeMB(200)

4.3% improvement

2) -Xmx256M, indexWriter.setMaxBufferSizeMB(200)

86.5% improvement

35Monday, June 7, 2010

Page 36: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2329: Parallel posting arrays - Performance

• With large heap there is a small improvement due to per-term memory savings

• With small heap the garbage collector is invoked much more often - huge improvement due to smaller number of objects (depending on doc sizes we have seen improvements of up to 400%!)

• With searchable RAM buffers we want to utilize all the RAM we have; with parallel arrays we can maintain high indexing performance even if we get close to the max heap size

Goal 2:Maintain high indexing performance with large RAM buffer, and independent of the query load

36Monday, June 7, 2010

Page 37: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

InvertedDocProducerInvertedDocProducer

InvertedDocConsumer

Today: Multi-threaded Indexing chain

DocumentsWriterIndexWriter

InvertedDocProducer

InvertedDocConsumerInvertedDocConsumer

Threads

Segment

Interleave

Indexing chain

37Monday, June 7, 2010

Page 38: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Today: Multi-threaded Indexing chain

• The interleaving step is quite expensive

• Flushing “stops the world”: No documents can be added during flushing/interleaving

• Multi-threaded code necessary in all IndexingChain classes, e.g. we have >10 *PerThread classes in the indexer package

38Monday, June 7, 2010

Page 39: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

DocumentsWriterPerThread

DocumentsWriterPerThread

LUCENE-2324: Single threaded indexing chain

DocumentsWriterPerThread

IndexWriter

InvertedDocProducer

InvertedDocConsumer

InvertedDocProducer

InvertedDocConsumer

InvertedDocProducer

InvertedDocConsumer

39Monday, June 7, 2010

Page 40: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

LUCENE-2324: Single threaded indexing chain

• Multiple per-thread DocumentsWriters write their own private segments

• Great simplification, many perThread classes can be removed (see 2324 patch)

• DocumentsWriterPerThreads can flush independently without “stopping the world”; interleaving step not necessary anymore

• This change reduces the concurrency problem we need to solve for RAM IndexReaders to a single-writer, multi-reader problem -> lock-free algorithms are now possible

40Monday, June 7, 2010

Page 41: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Searching DocumentsWriter’s RAM buffer

• Implement an IndexReader that shares the indexes data structures with DocumentsWriter

• Terms hashtable is used for fast term lookup

• TermDocs/TermPositions implementation for in-memory postinglists

• Sequence IDs for efficient deletes

• IndexReader needs to be able to switch automatically and on-the-fly from reader the RAM buffer to a flushed segment in case DocumentsWriter flushes its buffer while searches are in-flight

Goal 1:Allow IndexReaders to search on DocumentsWriter’s RAM buffer, while documents are being appended simultaneously to the same data structures

41Monday, June 7, 2010

Page 42: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency

• Having a single writer thread simplifies our problem: no locks have to be used to protect data structures from corruption (only one thread modifies data)

• But: we have to make sure that all readers always see a consistent state of all data structures -> this is much harder than it sounds!

• In Java, it is not guaranteed that one thread will see changes that another thread makes in program execution order, unless the same memory barrier is crossed by both threads -> safe publication

• Safe publication can be achieved in different, subtle ways. Read the great book “Java concurrency in practice” by Brian Goetz for more information!

• Going through all details could easily fill an entire talk. We’ll only look into a few examples here.

42Monday, June 7, 2010

Page 43: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• Each reader remembers the max. docID of the last completely indexed document at the time the reader was opened

• For each term we store the first docIDs it occurred in. We make sure the parallel array holding those first docIDs is properly initialized (visible to readers)

• When we lookup a term with an IndexReader, we compare the reader’s maxDocID with the first docID of the term; the term is only returned if maxDocID(reader) >= firstDocID(term); otherwise the lookup method returns term_not_found

• There are not “dirty reads” on integers in Java, meaning a thread either gets the old or the new value of a variable that another thread is writing too in parallel

43Monday, June 7, 2010

Page 44: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• If a reader tries to lookup a term that a writer is at the same time writing for the first time (term has not yet occurred in earlier documents) different things can happen:

-1 / 5

termIDint[] textPointer firstDocIDpostingsPointer

int[] int[] int[]

0123456

DocumentsWriter is currently adding term with ID=5; reader

either sees -1 (initial value for all terms) or the new ID=5

44Monday, June 7, 2010

Page 45: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• If a reader tries to lookup a term that a writer is at the same time writing for the first time (term has not yet occurred in earlier documents) different things can happen:

-1 / 5

termIDint[] textPointer firstDocIDpostingsPointer

int[] int[] int[]

0123456If reader gets -1, we’re done -

term is not found.

45Monday, June 7, 2010

Page 46: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• If a reader tries to lookup a term that a writer is at the same time writing for the first time (term has not yet occurred in earlier documents) different things can happen:

-1 / 5

termIDint[] textPointer firstDocIDpostingsPointer

int[] int[] int[]

0123456

If reader gets 5 we continue with reading the firstDocID of the

term

46Monday, June 7, 2010

Page 47: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• If a reader tries to lookup a term that a writer is at the same time writing for the first time (term has not yet occurred in earlier documents) different things can happen:

-1 / 5

termIDint[] textPointer firstDocIDpostingsPointer

int[] int[] int[]

-1 / 10

0123456

If reader sees -1 (initial value for all firstDocIDs) then it returns

term_not_found

47Monday, June 7, 2010

Page 48: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• If a reader tries to lookup a term that a writer is at the same time writing for the first time (term has not yet occurred in earlier documents) different things can happen:

-1 / 5

termIDint[] textPointer firstDocIDpostingsPointer

int[] int[] int[]

-1 / 10

0123456

If reader sees e.g. docID=10 it compares it with its maxDocID. If the doc was added after the reader was opened, it will stop

here too and return term_not_found; otherwise it’s

safe to access the term’s postinglist (see next slide)

48Monday, June 7, 2010

Page 49: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Concurrency - Example: term lookup

• After each document is fully indexed the writer thread is forced to cross a memory barrier

• When a reader is opened the opening thread is also forced to cross the same memory barrier

• A memory barrier can be as simple as a single volatile variable that multiple threads access

• Hence, visibility for all documents older than maxDocID is ensured for an IndexReader

49Monday, June 7, 2010

Page 50: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

- Introduction

- Near-realtime Search (NRT)

- Searching DocumentsWriter’s RAM buffer

‣ Sequence IDs

- Twitter prototype

- Roadmap

50Monday, June 7, 2010

Page 51: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Sequence IDs

51Monday, June 7, 2010

Page 52: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API

• void addDocument(Document doc);

• void updateDocument(Term delTerm, Document doc);

• void deleteDocuments(Term delTerm);

• void commit();

• All these methods are thread-safe

• But: in which order are they executed?

52Monday, June 7, 2010

Page 53: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API - Example

Thread 1:

addDoc(doc1);addDoc(doc2);

Thread 2:

deleteDocs(term);

• Problem: Will Thread 2 only delete doc1 or also doc2? Which state will the reader that Thread 3 opens “see”?

• Answer: It depends on Java’s thread scheduling which thread acquires the mutex first.

• It’s currently hard to write code that can track the order of calls and answer the question above.

term occurs in both docs

Thread 3:

IW.getReader();

53Monday, June 7, 2010

Page 54: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API

• void addDocument(Document doc);

• void updateDocument(Term delTerm, Document doc);

• void deleteDocuments(Term delTerm);

• void commit();

• long

• long

• long

• long

• All methods will return a sequence ID, which unambiguously indicate the order the operations were executed in

• An RAM IndexReader will also have a sequence ID that defines which snapshot of the index it can “see”

54Monday, June 7, 2010

Page 55: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API - Example

Thread 1:

addDoc(doc1);addDoc(doc2);

Thread 2:

deleteDocs(term);

• doc1 is added before delete; delete happens before doc 2 is added

• Thread 3’s reader will see doc 1

Thread 3:

IW.getReader();1

3 2 1

55Monday, June 7, 2010

Page 56: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API - Example

Thread 1:

addDoc(doc1);addDoc(doc2);

Thread 2:

deleteDocs(term);

• doc1 is added before delete; delete happens before doc 2 is added

• Thread 3’s reader will only see doc 2 (doc 1 will appear as deleted)

Thread 3:

IW.getReader();1

3 2 3

56Monday, June 7, 2010

Page 57: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API - Example

Thread 1:

addDoc(doc1);addDoc(doc2);

Thread 2:

deleteDocs(term);

• doc1 is added before doc2; delete happens after both docs are added

• Thread 3’s reader will see both docs

Thread 3:

IW.getReader();1

2 3 2

57Monday, June 7, 2010

Page 58: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

IndexWriter API - Example

Thread 1:

addDoc(doc1);addDoc(doc2);

Thread 2:

deleteDocs(term);

• doc1 is added before doc2; delete happens after both docs are added

• Thread 3’s reader will not see any docs (both will appear as deleted)

Thread 3:

IW.getReader();1

2 3 3

58Monday, June 7, 2010

Page 59: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

Deletes

59Monday, June 7, 2010

Page 60: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

X

deleteDoc(2);

Deletes

60Monday, June 7, 2010

Page 61: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

X X

deleteDoc(2);deleteDoc(5);

Deletes

61Monday, June 7, 2010

Page 62: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1

X X

IndexReader1

X X

Deletes

62Monday, June 7, 2010

Page 63: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);

IndexReader1

X X

X XX

Deletes

63Monday, June 7, 2010

Page 64: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

X X

X XX

IndexReader2

X XX

Deletes

64Monday, June 7, 2010

Page 65: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

X X

X XX

IndexReader2

X XX

!=

Deletes

65Monday, June 7, 2010

Page 66: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Today deletes are stored as BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

X X

X XX

IndexReader2

X XX

!=

we can’t share the same BitSet -> cloning necessary

Deletes

66Monday, June 7, 2010

Page 67: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Deletes

• Each IndexReader may need its own copy of the BitSet

• Especially for large segments the cloning quickly becomes very inefficient, if deletes and IndexReader (re)opens are frequent

• Solution: Utilize sequence IDs instead of BitSets

67Monday, June 7, 2010

Page 68: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);

1

1

68Monday, June 7, 2010

Page 69: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);

1 2

12

69Monday, June 7, 2010

Page 70: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1

IndexReader1

1 2

1 2

12

2

70Monday, June 7, 2010

Page 71: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);

IndexReader1

1 23

1 23

12

2

3

71Monday, June 7, 2010

Page 72: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

1 23

IndexReader21 23 1 23

12

2

3

3

72Monday, June 7, 2010

Page 73: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

• LUCENE-2324: Use array of sequence IDs instead of BitSets

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

1 23

IndexReader21 23 1 23

12

2

3

3

==

the same seqID array can be shared now

73Monday, June 7, 2010

Page 74: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Utilizing Sequence IDs for memory efficient deletes

Segment9 docs

deleteDoc(2);deleteDoc(5);open IndexReader1deleteDoc(0);open IndexReader2

IndexReader1

1 23

IndexReader21 23 1 23

12

2

3

3

boolean isDeleted = (seqId[doc] <= readerSeqID);

Reader1: seqId[0] = 3, readerSeqID = 2 -> isDeleted = falseReader2: seqId[0] = 3, readerSeqID = 3 -> isDeleted = true

• LUCENE-2324: Use array of sequence IDs instead of BitSets

74Monday, June 7, 2010

Page 75: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• No cloning necessary anymore

• Memory consumption for deletes does not increase when many IndexReaders are opened

Goal 3:Opening a RAM IndexReader should be so cheap, so that a new reader can be opened for every query (drops latency close to zero)

Utilizing Sequence IDs for memory efficient deletes

75Monday, June 7, 2010

Page 76: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Lucene’s IndexWriter handles two kinds of exceptions: Aborting exceptions (e.g. OutOfMemoryError) and non-aborting exceptions (e.g. document encoding problem)

• When an aborting exception occurs, then the IndexWriter tries to commit all docs to the index that were successfully flushed before the error occurred

• Problem: Today it’s not possible to know which documents made it into the index and which ones were dropped due to the error. Which docs do I have to reindex?

• Solution: IndexWriter.commit() will also return the sequence ID of the last write operation (add, delete, update) that was committed

Using sequence IDs for document tracking

76Monday, June 7, 2010

Page 77: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• An external log can be used to replay all operations that were lost due to the aborting exception

• It’s easy to find out which write operations need to be replayed by checking the sequence ID that commit() returns

Using sequence IDs for document tracking

77Monday, June 7, 2010

Page 78: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

- Introduction

- Near-realtime Search (NRT)

- Searching DocumentsWriter’s RAM buffer

- Sequence IDs

‣ Twitter prototype

- Roadmap

78Monday, June 7, 2010

Page 79: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Twitter prototype

79Monday, June 7, 2010

Page 80: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• Tweets are only 140 chars long

• Use 32-bit integers for postings: 24 bits for the docID (max segment size is 16.7M docs), 8 bits for the position (position can only have values 0-255; enough for tweets)

• Decoding speed significantly improved compared to delta and VInt decoding (early experiments suggest 5x improvement compared to vanilla Lucene with FSDirectory)

• In-memory postinglists can be traversed in reverse order -> early termination if time is a dominant factor of ranking score (as it usually is in realtime search)

Postinglist format

80Monday, June 7, 2010

Page 81: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• On a single machine we can (without much tuning yet):

• Index ~60,000 tweets/sec (very simple text analysis in the prototype)

• Search with ~15,000-20,000 queries/sec

• Lock-free algorithm: Results show, that indeed indexing and search performance are independent

Early performance experiments

81Monday, June 7, 2010

Page 82: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

TPS

Time

Early performance experiments

TPS

Time

Indexing with one thread while querying with multiple threads

Only indexing with one thread

82Monday, June 7, 2010

Page 83: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Early performance experiments

TPS

QPS

Indexing performance over varying query load

• No “trend” here: indexing performance pretty much independent of query load

• TPS goes down only if more threads are used than CPU cores are present, because thread scheduling becomes expensive

Goal 2:Maintain high indexing performance with large RAM buffer, and independent of the query load

83Monday, June 7, 2010

Page 84: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Realtime Search with Lucene

Agenda

- Introduction

- Near-realtime Search (NRT)

- Searching DocumentsWriter’s RAM buffer

- Sequence IDs

- Twitter prototype

‣ Roadmap

84Monday, June 7, 2010

Page 85: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

Roadmap

85Monday, June 7, 2010

Page 86: New Realtime Search with Lucene - Berlin Buzzwords2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/... · 2011. 1. 12. · Introduction • Lucene made great progress towards

• LUCENE-2329: Parallel posting arrays

• LUCENE-2324: Per-thread DocumentsWriter and sequence IDs

• LUCENE-2346: Change in-memory postinglist format

• LUCENE-2312: Search on DocumentsWriters RAM buffer

• IndexReader, that can switch from RAM buffer to flushed segment on-the-fly

• Sorted term dictionary (wildcards, numeric queries)

• Stored fields, TermVectors, Payloads (Attributes)

Roadmap

86Monday, June 7, 2010